Messages in this thread | | | Date | Wed, 17 Nov 1999 23:06:07 -0500 | From | "Theodore Y. Ts'o" <> | Subject | Re: serial port - ioctl's prevent subsequent reads |
| |
Date: Thu, 18 Nov 1999 00:26:11 +0100 (MET) From: David Monniaux <David.Monniaux@ens.fr>
using kernel 2.2.5 and glibc 2.1 (RedHat 6.0), I get the following weird behaviour: the serial port being -crtscts and clocal, the following program waits forever in tcdrain():
#include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <sys/ioctl.h>
main() { int fd, foo; char totor[300]; fd=3Dopen("/dev/ttyS0", O_RDWR); ioctl (fd, TIOCMSET, &foo); write(fd, totor, 300); fprintf(stderr, "maa\n"); tcdrain(fd); fprintf(stderr, "moo\n"); }
It seems that the system does not transmit any data. However, removing the ioctl line makes it run fine.
Why would i/o get blocked after such an ioctl?
It's very simple. You should never never call TIOCMSET raw and pass garbage to it. You should always call TIOCMGET, then modify whatever modem lines you want, and then call TIOCMSET. What you did by passing garbage to TIOCMSET was that you turned off the OUT2 line to the uart, which disabled interrupts to the UART. This caused the tcdrain to take a *long* time, since characters weren't moving all that rapidly with interrupts turned off.
[I'm becoming sick and tired of the serial driver second-guessing the programmer. First, even when clocal is on, it resets the modem lines on opening the device, which is plain stupid since clocal tells it to leave these lines alone.
That's not what CLOCAL means. Read the POSIX specification. POSIX specifically states CLOCAL means to ignore the modem control lines (specifically "wait until a connection is established", so it is referring to the RS-232 Carrier Detect line) for the purposes of determining whether or not open() should block. See sections 7.1.2.4 and sections 7.1.1.1.
As far as the serial driver's enabling DTR when the port is opened; this is necessary. In the normal case, when you're talking to a modem, you may want to set CLOCAL so that you don't get disconnected when the modem drops carrier detect. As discussed above, this is the definition of CLOCAL as defined by POSIX. However, DTR must be high or some modems won't pay attention to you at all (and this is specified by the RS-232 specification). So in the general case you have to raise DTR when you open the port, or a number of standard serial devices will refuse to function.
(Similarly, if the RS-232 port is configured as a DCE, the DTR line becomes the DSR line, and DSR has to be raised or some terminals will refuse to talk to the serial port.)
Also, normally DTR is not referred to as "modem control line" so your argument that CLOCAL means the serial driver shouldn't touch DTR is bogus for two different reasons.
Then it does weird things if I fiddle with them myself. I add that code similar to the one above worked under 2.0 / libc 5.]
That's because you wrote non portable code and didn't call TIOCMGET to obtain the current value before modifying them and calling TIOCMSET. You would have also been fine if you had used TIOCMBIC and TIOCMBIS.
The reason why it worked under Linux 2.0 was that under Linux 2.0 TIOCMSET didn't have the power to set the OUT1 and OUT2 UART lines, and I got a number of feature requests to allow the serial driver to do so. I did, but it meant making the serial driver more powerful and flexible at the cost of causing folks who wrote non-portable code to lose. I'd hardly called that second-guessing the programmer; I'm just assuming the programmer is writing good code. (Clearly that was a bad assumption.)
- 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/
| |