With the change from sio(4) to uart(4), tcdrain(3) broke. Now tcdrain(3) only tests if the characters have been delivered to the uart(4) subdriver, it does not wait for them to have actually been sent on the wire. This prevents half-duplex communications with CTS/RTS from working. This contradicts both our own manpage and The Open Group Standards. Fix: There don't seem to be a newbus uart(4) method to ask or wait until all transmitted characters have been sent. One is obviously necessary. How-To-Repeat: #define AZ(x) assert ((x) == 0) int j, fd; fd = open(), makeraw() etc. set speed 300BPS j = TIOCM_RTS; AZ(ioctl(fd, TIOCMBIS, &j)); assert(3 == write(fd, "FOO", 3)) AZ(tcdrain(fd)); AZ(ioctl(fd, TIOCMBIC, &j)); Observe that RTS flips high + low, long before the three characters make it out through the TXD pin.
I came across the same problem: I need to switch the transmitter of an external RS232/RS485 converter on before satarting transmittision and off afterwards using RTS. My quick driver hack is to always call the chip-specific drain function whenever there is a request to turn off RTS. This is my patch to the 16550 code: --- uart_dev_ns8250.c.orig 2015-03-04 13:37:04.000000000 +0100 +++ uart_dev_ns8250.c 2015-03-04 13:40:05.000000000 +0100 @@ -886,6 +886,10 @@ } } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); uart_lock(sc->sc_hwmtx); +#ifdef UART_HACK_DRAIN_RTSOFF + if ((sig & SER_DRTS) && !(sig & SER_RTS)) + ns8250_drain(bas, UART_DRAIN_TRANSMITTER); +#endif ns8250->mcr &= ~(MCR_DTR|MCR_RTS); if (new & SER_DTR) ns8250->mcr |= MCR_DTR; The patch is against head but has been tested with 9.1 using a scope with protocol analyzer function. I did not look into the other chips' code so may it will not universally work.
For bugs matching the following conditions: - Status == In Progress - Assignee == "bugs@FreeBSD.org" - Last Modified Year <= 2017 Do - Set Status to "Open"