AxlSerial — serial-port enumeration + line-setting readout
Serial-port enumeration via EFI_SERIAL_IO_PROTOCOL.
Header: <axl/axl-serial.h>. Two layers over EFI_SERIAL_IO_PROTOCOL:
a read-only descriptor probe (enumerate handles, read each port’s line
settings — baud, framing, timeout, FIFO depth — and modem
control/status lines), and byte I/O for moving raw bytes over a
chosen port. For console byte streams use <axl/axl-stream.h>; this
is the lower-level per-port path (e.g. talking to a BMC’s SOL / a
device on a specific UART).
Lazy on first call: AxlSerial locates the serial-I/O handles once with
LocateHandleBuffer and caches the set for the image lifetime. On
platforms with no serial ports every call returns NULL / AXL_ERR
cleanly.
Cursor-style enumeration matches axl_block_next / axl_usb_next and
returns the firmware AxlHandle directly, so position is recovered
from the handle you pass back — no hidden shared cursor:
AxlHandle h = NULL;
while ((h = axl_serial_next(h)) != NULL) {
AxlSerialMode m;
AxlSerialControl c;
if (axl_serial_get_mode(h, &m) == AXL_OK) {
axl_printf("Uart(%u,%u,parity=%u,stop=%u)\n",
m.baud_rate, m.data_bits, m.parity, m.stop_bits);
}
if (axl_serial_get_control(h, &c) == AXL_OK && c.cts) {
axl_printf(" CTS asserted\n");
}
}
Byte I/O
To move bytes over a port, open an AxlSerial on one of the enumerated
handles, optionally set the line mode, then read/write:
AxlSerial *s = NULL;
axl_serial_open(h, &s); // h from axl_serial_next
axl_serial_set_mode(s, &(AxlSerialMode){ .baud_rate = 115200,
.data_bits = 8 });
size_t written = 0, got = 0;
axl_serial_write(s, "AT\r\n", 4, &written);
axl_serial_read(s, buf, sizeof buf, &got); // non-blocking; got may be 0
axl_serial_close(s);
EFI_SERIAL_IO exposes no receive event, so for loop-driven input
axl_serial_read_async(s, loop, poll_ms, cb, user) registers a timer
that drains the port each tick and calls cb with whatever arrived
(pick poll_ms to suit the UART rate; 5-10 ms for an interactive
console). One async receive per port; axl_serial_close removes the
source.
Device-path text needs no extra API: the same AxlHandle resolves
through the existing axl_handle_get_protocol(h, "device-path", ...)
axl_device_path_to_text()(both in<axl/axl-sys.h>).
parity and stop_bits are raw enum codes the consumer names (e.g.
"N", "8N1"); baud_rate is the firmware’s UINT64 BaudRate
narrowed to 32 bits (every real UART rate fits).
API Reference
Serial-port enumeration and line-setting readout.
Enumerates the handles publishing the firmware’s serial-I/O protocol and reads each port’s line settings (baud, framing, timeout, FIFO depth) and modem control/status lines. This is a read-only descriptor probe for inventory and diagnostics — it does not open a port, transmit, or receive. (Console byte I/O is <axl/axl-stream.h>; this is the lower-level port descriptor.)
Cursor-style iteration matches the other platform readers and returns the firmware AxlHandle directly:
AxlHandle h = NULL;
while ((h = axl_serial_next(h)) != NULL) {
AxlSerialMode m;
if (axl_serial_get_mode(h, &m) == AXL_OK) {
// ... report Uart(baud, data, parity, stop) ...
}
}
Device-path text needs no new API: the same AxlHandle resolves through the existing axl_handle_get_protocol(h, "device-path", ...) + axl_device_path_to_text() (both in <axl/axl-sys.h>).
Line-setting fields are raw readouts; the consumer names the parity/stop-bit codes (e.g. “N”, “8N1”).
Typedefs
-
typedef struct AxlLoop AxlLoop
-
typedef struct AxlSerial AxlSerial
Opaque open serial port. Owns no firmware resource beyond the borrowed protocol pointer (the port is firmware-owned); axl_serial_close frees the wrapper and removes any async-read source.
-
typedef void (*AxlSerialReadFn)(const void *data, size_t len, void *user)
Async receive callback — invoked from the loop with the bytes read this poll tick (
len> 0).datais owned by the library (valid only for the call); copy what you need.
Functions
-
AxlHandle axl_serial_next(AxlHandle prev)
Iterate handles publishing the serial-I/O protocol.
Cursor-style enumeration: pass NULL to get the first serial handle, then pass each returned handle back to get the next. Returns NULL once exhausted (including when no serial ports exist).
The handle set is located once and cached for the image lifetime (like AxlBlock / AxlUsb) — a port that appears afterward will not show up; the cache mirrors the boot device set. Position is recovered from the handle you pass back, not a hidden shared cursor: passing NULL — or any handle not in the cached set — starts again from the first port, and independent walks do not interfere. The returned handle is firmware-owned (do not free) and valid to pass to the readers below and to
axl_handle_get_protocol(h, "device-path", ...).- Parameters:
prev – previous handle, or NULL to start
- Returns:
next serial-I/O handle, or NULL at end of enumeration.
-
int axl_serial_get_mode(AxlHandle handle, AxlSerialMode *out)
Read a serial port’s current line settings.
- Parameters:
handle – handle from axl_serial_next
out – [out] populated on success
- Returns:
AXL_OK on success, AXL_ERR if
handledoes not publish the serial-I/O protocol oroutis NULL.
-
int axl_serial_get_control(AxlHandle handle, AxlSerialControl *out)
Read a serial port’s modem control/status lines.
Calls the protocol’s GetControl and decodes the handshake bits.
- Parameters:
handle – handle from axl_serial_next
out – [out] populated on success
- Returns:
AXL_OK on success, AXL_ERR if
handledoes not publish the serial-I/O protocol, the GetControl call fails, oroutis NULL.
-
int axl_serial_open(AxlHandle handle, AxlSerial **out)
Open a serial port for byte I/O.
handleis a serial-I/O handle from axl_serial_next. The port’s current line settings are left as-is (call axl_serial_set_mode to change them).- Parameters:
handle – handle from axl_serial_next
out – [out] open port on success
- Returns:
AXL_OK with
outset; AXL_ERR on NULL args, a handle that does not publish the serial-I/O protocol, or allocation failure.
-
void axl_serial_close(AxlSerial *s)
Close a serial port opened by axl_serial_open.
Removes any axl_serial_read_async source and frees the wrapper. Does not reset the underlying firmware port. NULL-safe.
- Parameters:
s – port (NULL-safe)
-
int axl_serial_set_mode(AxlSerial *s, const AxlSerialMode *mode)
Set the port’s line settings (baud / framing / timeout).
Maps to the protocol’s SetAttributes. A zero field requests the device default (per the UEFI spec).
modeuses the same field encoding as axl_serial_get_mode (parity / stop_bits raw codes).- Parameters:
s – open port
mode – desired settings
- Returns:
AXL_OK on success; AXL_ERR on NULL args or a SetAttributes failure (e.g. an unsupported baud/framing combination).
-
int axl_serial_write(AxlSerial *s, const void *buf, size_t len, size_t *out_written)
Write bytes to the port (best-effort within the port’s timeout).
Writes up to
lenbytes;out_written(optional) receives the count actually transmitted. A short write (firmware timeout) is not an error —out_writtentells the caller to retry the remainder.- Parameters:
s – open port
buf – bytes to send
len – number of bytes
out_written – [out] bytes transmitted (NULL = don’t care)
- Returns:
AXL_OK on success (possibly short — see
out_written); AXL_ERR on NULLs/bufor a device error.
-
int axl_serial_read(AxlSerial *s, void *buf, size_t cap, size_t *out_read)
Read available bytes from the port (non-blocking).
Returns immediately with whatever is buffered (up to
cap).out_readreceives the count — zero is a normal “nothing available right now” result, not an error. For a continuous receive, prefer axl_serial_read_async.- Parameters:
s – open port
buf – [out] receive buffer
cap – buffer capacity in bytes
out_read – [out] bytes read (0 = none available)
- Returns:
AXL_OK (with
out_readpossibly 0); AXL_ERR on NULLs/buf/out_read, zerocap, or a device error.
-
int axl_serial_read_async(AxlSerial *s, AxlLoop *loop, size_t poll_ms, AxlSerialReadFn cb, void *user)
Start a loop-integrated receive: poll the port and deliver bytes.
Registers a
poll_mstimer onloop; each tick drains the port and, if any bytes arrived, invokescbwith them. EFI_SERIAL_IO exposes no receive event, so this is a poll (not an interrupt) — pickpoll_msto suit the UART rate (e.g. 5-10 ms for an interactive console). Only one async receive per port; a second call replaces the first. The source is removed by axl_serial_close.- Parameters:
s – open port
loop – event loop
poll_ms – poll interval in milliseconds (> 0)
cb – receive callback
user – caller context
- Returns:
AXL_OK on success; AXL_ERR on NULL args, zero
poll_ms, or if the timer source could not be added.
-
struct AxlSerialMode
- #include <axl-serial.h>
Line settings for a serial port.
Typed projection of the firmware’s
SERIAL_IO_MODE(current attributes).parityandstop_bitsare raw enum codes the consumer maps to names; the firmware fields are:parity: 0 Default, 1 None, 2 Even, 3 Odd, 4 Mark, 5 Space
stop_bits: 0 Default, 1 OneStopBit, 2 OneFive, 3 Two
Public Members
-
uint32_t baud_rate
current baud rate; 0 = device’s designed speed (firmware field is UINT64, narrowed to 32 bits — every real UART rate fits)
-
uint32_t data_bits
data bits per character (5-8; 0 = device default)
-
uint8_t parity
parity code (EFI_PARITY_TYPE raw)
-
uint8_t stop_bits
stop-bits code (EFI_STOP_BITS_TYPE raw)
-
uint32_t timeout
receive/transmit timeout in microseconds (0 = device default)
-
uint32_t receive_fifo_depth
receive FIFO depth in bytes
-
struct AxlSerialControl
- #include <axl-serial.h>
Modem control/status lines for a serial port.
Decoded from the protocol’s GetControl bitmask. These are the status/handshake lines a diagnostic view reports; the consumer formats them.