Brijesh-Thakkar opened a new pull request, #20842:
URL: https://github.com/apache/nuttx/pull/20842
**Title:** drivers/serial/uart_16550: Add hooks for board-defined UART ports
(stage 1)
*Refs #18895 (does not fix it, stage 2 follows).*
## Summary
Issue #18895 asks for the 16550 driver to be usable from board code: register
as many UARTs as needed, control interrupt registration, and define board
Kconfig for the active ports. This is stage 1 of a staged approach. It adds
the small building blocks that a board needs and changes nothing for existing
users. The object model (a `struct u16550_port_s` with a
`u16550_dev_init()`,
shaped like the one in the PL011 refactor, #18837) and board migrations come
in stage 2, so this PR does not close the issue.
The hooks have no in-tree user in this PR by design, to keep it reviewable
and regression-free. Stage 2 adds `struct u16550_port_s` and a board user,
and
#19478 (RK3506) can drop its console accessor and hard-coded LSR polling
by using `irq < 0` + `u16550_rxpoll()`. If you prefer, I can fold stage 2
into
this PR instead.
What is added:
1. **`g_u16550_ops` is always built and exported.** The default
getreg/putreg/isr ops used to be `static` and compiled only if one of
`CONFIG_16550_UART0..3` was set, so a board with no static UART (or the
PCI driver alone) could not reuse them. They are now declared in
`uart_16550.h`.
2. **Optional `attach` / `detach` members in `struct u16550_ops_s`.** If
NULL
(every existing user), `u16550_attach()` / `u16550_detach()` do exactly
what
they did before (`irq_attach()` + `up_enable_irq()`, and
`up_disable_irq()` + `irqchain_detach()`). A board can supply its own,
for
example for an IRQ shared with another UART.
3. **`irq < 0` means "no interrupt".** The default attach/detach then skip
the
interrupt controller and `txint()` sends by polling, like
`CONFIG_16550_POLLING`. This is an opt-in for board-defined ports; ports
configured through Kconfig always have `irq >= 0`.
4. **`u16550_rxpoll(FAR uart_dev_t *dev)`.** If LSR.DR is set it calls
`uart_recvchars()`, as the RX interrupt would. A board whose RX interrupt
cannot be used can poll with it instead of reaching into the driver (for
example with a console accessor and a hard-coded LSR address).
5. **`uart_pci_16550`: fail the probe when no IRQ is available.**
`pci_get_irq()` can return a negative errno (e.g. `-ENOTSUP`) and it was
stored unchecked. With item 3 that value would have turned a loud
`irq_attach()` failure at `open()` into a silently polled port, so the
probe now fails with the error instead.
6. **Hooks are compiled out unless needed.** Items 2 and 3 are only active
with the new hidden option `CONFIG_16550_PORT_HOOKS` (default n, no
prompt),
which a board that defines its own ports selects. Without it two small
macros make the compiler drop that code, with no `#ifdef` at the branch
sites.
Commits (each builds on its own):
```
drivers/serial/uart_16550: Always build the default ops
drivers/serial/uart_16550: Add optional attach/detach ops
drivers/serial/uart_16550: Allow UARTs without an interrupt
drivers/serial/uart_16550: Add u16550_rxpoll()
drivers/serial/uart_pci_16550: fail probe when no IRQ is available
drivers/serial/uart_16550: Compile out the port hooks unless selected
```
## Impact
- **Users / boards:** none. No defconfig, board or arch file is changed.
`u16550_earlyserialinit()` / `u16550_serialinit()`, `u16550_bind()` and all
existing symbols keep their signatures and behavior. The only Kconfig
change is the new hidden `16550_PORT_HOOKS`; the `savedefconfig` output of
every defconfig that uses the driver is unchanged.
- **API:** additive only: `g_u16550_ops`, `u16550_rxpoll()`, and two new
trailing members of `struct u16550_ops_s`. Code that initializes
`u16550_ops_s` with designated initializers (as the in-tree PCI driver
does)
is unaffected; positional initializers would need the two new members.
- **PCI:** the only behavior change. A PCI UART whose controller cannot
provide an IRQ (`pci_get_irq() < 0`) now fails the probe instead of being
registered and failing at `open()`. A port with no usable IRQ could not be
opened before either (the console would have failed to open), so no working
configuration is affected.
- **Size** (this PR vs `master` `d0886af95d`, GCC 15.2, default flags of each
defconfig, whole image `text+data+bss`):
| Config | Image | `uart_16550.o` text |
|---|---|---|
| qemu-intel64:nsh | 8807937 -> 8807969 (**+32 B**) | 2607 -> 2764 |
| qemu-i486:nsh | 485177 -> 485337 (**+160 B**) | 2602 -> 2739 |
| qemu-intel64:nsh_pci | 8774525 -> 8774561 (+36 B) | 2308 -> 2458 |
| qemu-intel64:nxterm | 30243123 -> 30243223 (+100 B) | 3761 -> 4016 |
Without option 6 the growth was +128 B / +372 B for the first two rows.
What
remains is the two extra pointers in each ops table and the new
`u16550_rxpoll()`, which the linker drops where unused sections are
collected (the intel64 images).
- **Documentation:** the 16550 driver has no documentation page. The new
API is documented in `uart_16550.h`. Stage 2 should add one.
- **Security / build process:** none.
## Testing
**Testing was done on QEMU only. I have no real 16550 hardware, so none of
this has run on a real board. Maintainers and users with 16550 boards (and
AX99100 PCI cards) are asked to test it.**
**Host:** Ubuntu 26.04, Linux 7.0.0-38, x86_64, GCC 15.2.0, QEMU 10.2.1 with
KVM (`-cpu host -enable-kvm`), `tools/configure.sh` + `make`. Baseline is
`master` at `d0886af95d`; the runtime results were produced on the baseline
and on this branch with the same procedure and compared.
**Build** (no new warnings): qemu-intel64 `nsh`, `nsh_pci`, `nsh_pci_smp`,
`knsh_romfs_pci`, `ostest`, `nxterm`; qemu-i486 `nsh`.
`tools/checkpatch.sh -m -g d0886af95d..HEAD`: all checks pass.
**Runtime (QEMU)**: NSH prompt, typed input (RX, typed character by
character), long TX (`help`, `cat /proc/meminfo`), `ls /dev`:
| Config | Console | Result (baseline / this PR) |
|---|---|---|
| qemu-intel64:nsh | COM1, 16550 (port I/O) | pass / pass |
| qemu-i486:nsh | COM1, 16550 | pass / pass |
| qemu-intel64:nxterm | QEMU `pci-serial` (PCI 16550), serial NSH fallback |
pass / pass |
| qemu-intel64:ostest | COM1 | ostest exits 0 / ostest exits 0 |
`nsh_pci`, `nsh_pci_smp` and `knsh_romfs_pci` target an AX99100 card
(vendor `0x125b`, device `0x9100`) and cannot be booted under QEMU, whose
`pci-serial` has a different id; they were only built. The PCI driver was
exercised through `nxterm`, which uses wildcard PCI ids.
Excerpt (this PR, `nxterm`, PCI console):
```
pci_u16550_register: Register /dev/ttyS0
...
/dev:
console
null
pci
ptmx
random
telnet
ttyS0
urandom
zero
```
**Kconfig:** `olddefconfig` + `savedefconfig` round trip on all 77 defconfigs
that mention `CONFIG_16550_`: output identical to the baseline run (74 files
unchanged; 3 files differ from their committed defconfig by
`CONFIG_EXAMPLES_POPEN` in both runs, an apps-tree version mismatch of my
local checkout, unrelated).
**Syntax-only (clang 21, `-fsyntax-only`)** of `uart_16550.c` and the arch
serial file for: rv-virt (rv32, rv64), canmv230 (k230), pocketbeagle2
(am62x), orangepi-5-pro (rk3588), avaota-a1 (a527), t3-gem-o1 (am67),
csk6011a-nano, moxa: no errors and no new warnings. `uart_16550.c` was also
syntax-checked with `CONFIG_16550_PORT_HOOKS` forced on (x86_64).
**Not tested:**
- Any real hardware: all runtime tests are QEMU.
- Boot of RISC-V (rv-virt, k230, jh7110, ...), arm64 (am62x, rk3588, a527),
Arm (am67, csk6, moxart), MIPS and OR1K 16550 users: compile-checked only.
- AX99100 hardware.
- `CONFIG_16550_UARTn_DMA` configurations.
- The new hooks (`attach`/`detach`, `irq < 0`, `u16550_rxpoll()`) are not
used
by any in-tree board yet and are compiled out in every existing
configuration, so the runtime tests above show "no regression", not the new
behavior. Stage 2 will exercise them.
## AI assistance
This change was developed with Claude Code (`claude-sonnet-5-5`). Every
commit carries an `Assisted-by:` field as required by CONTRIBUTING.md. I
reviewed the diff and certify the DCO with my `Signed-off-by`. The design
follows the discussion in #18895 and the review of #18837.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]