Re: serial.c (race?)

tytso@mit.edu
Sun, 17 Oct 1999 21:56:27 -0400


Date: Fri, 15 Oct 1999 19:30:10 +0200 (MEST)
From: kees <kees@schoen.nl>

I ran into an effect which might be a race in the serial drivers of
2.2.12. I run a program which communicates via the Hart protocol. This is
a simplex protocol and uses the IO port more or less like RS485.

It's not a race condition in the serial driver, as much as it is a race
in the way you're trying to use the serial driver.

The problem is that the serial driver doesn't support half-duplex
communications natively. I've considered putting support directly in
the kernel, but there's no standard protocol for half-duplex
communications. Different devices have different requires around how
long to wait after raising RTS before you start transmitting, and how
long to wait after transmitting to drop RTS. Some devices require that
you monitor DTR before trying to raise RTS, and so on. So it's rather
painful to support half-duplex serial communicatons in anything
resembling a general fashion.

The fact that the serial driver doesn't support half-duplex
communications is forcing you to try to support it in user space. There
are a number of reasons why you might be losing. One is that on faster
machines you may be violating some timing constraint on when RTS needs
to be raised or lowered.

The other problem, which seems to be the one that you've discovered, is
that the rs_write() routine doesn't actually send characters out the
serial port, instead it filles the kernel's internal serial write
buffers which are then sent out at interrupt time. ("Pseudo-DMA", in
BSD speak). You're polling the UART's LSR register, and sometimes (on
faster CPU's) this is happening before UART FIFO has a chance to be
loaded.

I added a check in my program after the first write call to wait for the
drop of the Transmitter Empty bit first before to proceed. That
worked.

That, or perhaps putting in a usleep after all of the write calls before
polling the transmitter empty bit may be your best bet. The problem is
that putting this code into the kernel would force me to put in
interlocks that would degrade the performance in the common case, which
I'm very hesitent to do since half-duplex operation is *not* commonly
used.

The other solution is to put some kind of half-duplex support into the
driver, but accept that different users may have to customize the kernel
to add their specific device-specific timing constraints, or
dependencies on other RS-232 signals. We could try generalizing the
support, but I suspect there will also be some kind of wierd-sh*t
hardware that demands something new that we hadn't thought of.

- Ted

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/