Path: utzoo!mnetor!uunet!munnari!otc!metro!basser!natmlab!dmsadel!augean!sibyl!ian From: ian@sibyl.eleceng.ua.OZ (Ian Dall) Newsgroups: comp.bugs.sys5 Subject: Bug in TCSETA ioctl? Message-ID: <107@sibyl.eleceng.ua.OZ> Date: 6 Apr 88 07:12:18 GMT Reply-To: ian@sibyl.OZ (Ian Dall) Organization: Engineering, Uni of Adelaide, Australia Lines: 142 There appears to be a bug in the code to impliment the TCSETA[F,W] code Sys5.2 rel 2. I would be interested to know if this bug is a) already known or b) fixed in later releases. According to the "termio" man pages "TCSETA Set the parameters associated with the terminal from the structure referenced by arg. The change is immediate. TCSETAW Wait for the output to drain before setting the new parameters. This form should be used when changing parameters that will affect output." The implication is that the converse of the last sentence holds. And that providing your change does not affect output post processing TCSETA should be fine. In practice this turns out not to be the case. I only have a binary licence which does include the hardware tt driver source but not the generic tt driver stuff. The hardware tt driver calls ttiocom and if it returns non zero goes and stuffs things in the DUART registers to set up baud rates no of stop bits etc. Not too surprisingly this tends to corrupt anything the DUART is in the process of outputing. Using adb on the kernal to find out what ttiocom does (remember I don't have the source) reveals that the code must be some thing like: ttiocom(.........) { . . . switch ( command ) case TCSETAW: case TCSETAF: ttywait(...); if (command == TCSETAF) ttyflush(....); case TCSETA: . . . /* code to get parameters from users area */ return(1); case TCGETA: . . . /* code to put parameters into users area */ break; case TCSBRK: . . . break; case TCXONC: . . . break; case TCFLSH: . . . break; return(0); } I contend that this code should only return 1 if the HARDWARE setup has changed. Many (most?) TCSETAs will NOT change the hardware setup. Something like replacing the "return (1);" with if ( old_c_cflag == c_cflag ) break; else return (1); should do the trick. Do later SysVs do this? Perhaps other hardware is less fussy and don't get upset by setting the hardware registers to the same as they already are. Here is a test program so you can see if your system exhibits this bug. If the output is garbled you have the bug. # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by ian on Wed Apr 6 16:07:04 CST 1988 # Contents: checktermio.c echo x - checktermio.c sed 's/^@//' > "checktermio.c" <<'@//E*O*F checktermio.c//' #include #include #define TSET TCSETA int kbd_count; char *kbd_ptr, kbd_buffer[256]; char longstring[] = "The quick brown fox jumped over the lazy dogs back and\ made him howl horribly.\n"; main() { register i; for (i=1; i < 20; i++) { printf(longstring); read_avail_input(); } } read_avail_input () { struct termio tnow, told; if (ioctl (fileno (stdin), TCGETA, &tnow) < 0) return; told = tnow; tnow.c_lflag &= ~ICANON; tnow.c_cc[VMIN] = 0; tnow.c_cc[VTIME] = 0; ioctl (fileno (stdin), TCSETA, &tnow); kbd_ptr = kbd_buffer; kbd_count = read (fileno (stdin), kbd_buffer, sizeof kbd_buffer); ioctl (fileno (stdin), TCSETA, &told); } @//E*O*F checktermio.c// chmod u=rw,g=r,o=r checktermio.c exit 0