Re: serial.c (half duplex support)

Riley Williams (rhw@MemAlpha.CX)
Wed, 20 Oct 1999 18:36:16 +0100 (GMT)


Hi Ted.

>> 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.

Ted, I know you're against adding variables to the Config.in trees,
but to me, this sounds like some sort of "Enable half duplex serial
support" variable would be the best way to go, as that would provide
the best of both ways:

1. If (as it normally would be) the kernel is compiled with
the said option set to "n", then the serial driver would
remain as it currently is.

2. For those (like Kees) who need it, the kernel could be
compiled with the said option set to "y". In this case,
it would define an additional pair of routines to handle
the switching from send to receive and back again.

Since these additional routines are neither defined nor called in the
first case, it would be possible for those needing half duplex support
to develop it without impacting on those who don't need it.

Certainly at this stage, any such variable would be firmly planted in
the $CONFIG_EXPERIMENTAL tree, and would remain there until the API in
question was fully developed.

> 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.

One thing a procedure like the above would do is to move the decisions
re half/full duplex from the runtime code to the initialisation code.
In other words, the effective result would be that the equivalent of
the following (much simplified) script would get run:

Q> #!/bin/bash
Q> if [ $# -ne 1 ]; then
Q> echo "Usage: `basename $0` port" >&2
Q> exit 127
Q> fi
Q> setserial $1 duplex=half
Q> while read TEXT ; do
Q> echo "$TEXT" > $1
Q> read TEXT < $1
Q> echo "$TEXT"
Q> done
Q> setserial $1 duplex=full

The above assumes that each end sends exactly one line of text each
time, but any production code would need to handle the case where one
end sends several lines before the other sends anything, of course.

>> 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.

Similar to the way the IrDA tree supports different types of IR
dongle?

Best wishes from Riley.

PS: The kernel versions page is now back online at the URL below, and
includes separate sublists both for each kernel series, and for
each year of development.

+----------------------------------------------------------------------+
| There is something frustrating about the quality and speed of Linux |
| development, ie., the quality is too high and the speed is too high, |
| in other words, I can implement this XXXX feature, but I bet someone |
| else has already done so and is just about to release their patch. |
+----------------------------------------------------------------------+
* http://www.memalpha.cx/Linux/Kernel/

-
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/