[comp.sys.sun] printer connections on Suns

gdmr@uunet.uu.net (George D M Ross) (01/27/89)

xilinx!sol!kevin@uunet.uu.net (Kevin Kelleher) writes:
>I have been having similar with problems with my printer dropping pieces
>of files on an HP Laserjet printer to my Sun 3/280 under OS 4.0.1.  After
>some experimentation I have decided it is probably a tty driver problem.

We came to much the same conclusion when we upgraded to 4.0 -- printers
and plotters would lose the end of files sent to them.  After some
experimentation with cat and dumb terminals we decided that XON/XOFF was
being zapped when the final close of the device was done.  To test it,
hang a terminal on a serial port and cat a largish file to it.  Observe
that flow control works while the cat is executing but not for the tail of
the file which is still in the output buffer after the cat terminates.  If
you then try again, but this time cat from the terminal as well as to it
you will find that flow control works all the way through.  We "solved"
the problem by having our output filters wait around a while (device
dependent) after the last of the output has gone before closing the output
device.  There may be some option settings which we missed which would fix
this -- we didn't try too hard as we had a filter which did more-or-less
the right job.  An alternative for dumb printers might be to cat the
device to /dev/null in your rc file (we didn't bother trying this, but
based on our tests it seems plausible).  When we come to installing our
laser printers we'll probably have to write some trivial program which
simply opens the device and then sleeps forever, as the two suggestions
above either won't be feasible or won't work.

George D M Ross					..!mcvax!ukc!ecsvax!gdmr
Department of Computer Science			gdmr@ecsvax.ed.ac.uk
Edinburgh University				+44 31 667-1081 x2730

perl@philabs.philips.com (Robert Perlberg) (02/16/89)

In my HP filter, I wait for the output to flush with this code:

#include <stdio.h>
#include <sgtty.h>

outputwait(fd)
int fd;
{
	int outchars;

	while(ioctl(fd, TIOCOUTQ, &outchars) == 0 && outchars > 0)
	{
		sleep(1);
	}
}

Robert Perlberg
Dean Witter Reynolds Inc., New York
phri!{dasys1 | philabs | mancol}!step!perl

guy@uunet.uu.net (Guy Harris) (03/02/89)

>In my HP filter, I wait for the output to flush with this code:
>...
>	while(ioctl(fd, TIOCOUTQ, &outchars) == 0 && outchars > 0)

Wow.  That probably works (although I don't know that TIOCOUTQ will always
give the right answer), but under 3.x or 4.0 (or any V7/BSD-style tty
driver) the following should work better:

	struct sgtty sgttyb;

	(void) ioctl(fd, TIOCGETP, &sgttyb);
	(void) ioctl(fd, TIOCSETP, &sgttyb);

since, as it says in the 4.3-tahoe TTY(4):

	TIOCSETP
	     Set the parameters according to the pointed-to "sgttyb"
	     structure.  The interface delays until output is quiescent,
	     then throws away any unread characters, before changing the
	     modes.

Since you do a TIOCGETP followed immediately by a TIOCSETP, the modes
aren't changed; the only effects of the TIOCSETP are 1) it waits for
output to drain and 2) it flushes all input.  The latter is an unfortunate
side-effect, but it may not be a problem here.

I think all of the variants mentioned above, except 4.0, say much the same
thing.  4.0's TTCOMPAT(4M) basically says "TIOCSETP gets turned into a
TCSETSF", and 4.0's TERMIO(4) says about TCSETSF:

     TCSETSF        The argument is a pointer to a termios struc-
                    ture.   The  current  terminal parameters are
                    set from the values stored in that structure.
                    The change occurs after all characters queued
                    for output have been transmitted; all charac-
                    ters  queued for input are discarded and then
                    the change occurs.

which is basically the same set of side-effects as TIOCSETP.

In 4.0, though, and other systems that offer an S5-compatible tty driver,
there is an even better way; again from TERMIO(4):

     TCSBRK         The argument is an int value.  Wait  for  the
                    output  to drain.  If the argument is 0, then
                    send  a  break  (zero-valued  bits  for  0.25
                    seconds).

If the argument is *not* zero, no break is sent, so

	ioctl(fd, TCSBRK, 666);	/* insert your number here - beastly, eh? */

will just wait for output to drain.