rsalz@bbn.com (Rich Salz) (02/23/88)
Submitted-by: Gregg Townsend <gmt@MEGARON.ARIZONA.EDU> Posting-number: Volume 13, Issue 58 Archive-name: 4.3autobaud This program does automatic baud rate detection under 4.3 BSD Unix. That is, you send it a carriage return and it figures out your baud rate. It depends on the hardware response to a speed mismatch, but the technique dates back at least to TOPS-10 and probably much earlier. I've seen it work on several systems; we're running this code on Vaxes. Note that only certain speeds work; generalizing it to handle all possible speeds is decidedly nontrivial. The set here (300, 1200, 2400, 9600) is sufficient for us. Autobaud was originally written to handle terminals coming in through a port switch that intercepts BREAKs. Now we run it on nearly all incoming lines as a replacement for getty(8). (We tried, not too hard, to get getty's baud detection code to work; the tangled code, comments referencing Micom, and omission of the feature from the published documentation were all discouraging.) Gregg Townsend / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721 +1 602 621 4325 gmt@Arizona.EDU {allegra|noao|ihnp4}!arizona!gmt ---------------------------- cut here ----------------------------------- # To unbundle, sh this file echo unbundling Makefile 1>&2 cat >Makefile <<'AlBeRtEiNsTeIn' autobaud: autobaud.c ; cc -O -s -o autobaud autobaud.c AlBeRtEiNsTeIn echo unbundling autobaud.8 1>&2 cat >autobaud.8 <<'AlBeRtEiNsTeIn' .TH AUTOBAUD 8 "15 April 1987" "University of Arizona" .SH NAME autobaud \- terminal speed detection .SH SYNOPSIS \fB/etc/local/autobaud [ \-l ] [ \fIttyname\fB ] .SH DESCRIPTION .I Autobaud is a simpler replacement for .IR getty (8), the crucial difference being that .I autobaud performs line speed detection as distinguished from cycling. The speeds recognized are 300, 1200, 2400, and 9600 baud. Autobaud expects the user to type a carriage return and will loop until one is received. .PP If .I ttyname is given, .I autobaud samples .RI /dev/ ttyname instead of standard input. The .B \-l option is normally set in /etc/ttys and causes .I autobaud to exec .IR login (1) after determining the speed. .PP Autobaud sets these terminal parameters: any parity, no tabs, echo, erase ^H, kill ^U. .SH FILES .PP /etc/ttys .br /dev/\fIttyname\fP .SH "SEE ALSO" init(8), getty(8), login(1) .SH BUGS .PP BREAK and NUL have no effect, but typing any other character is likely to cause .I autobaud to set the speed incorrectly. .PP Theory says that 600 baud should also work, but it doesn't. AlBeRtEiNsTeIn echo unbundling autobaud.c 1>&2 cat >autobaud.c <<'AlBeRtEiNsTeIn' /* autobaud.c - determine tty speed of standard input (for 4.3 BSD Unix) * * Autobaud reads standard input at 2400 baud. Assuming a carriage return * is typed, the bit pattern received is used to select and set the "true" * speed. This works for speeds of 300, 1200, 2400, and 9600 baud. In theory * 600 should also work, but empirically a 00 character is read and it doesn't. * Any other speed, or any character other than a carriage return, is likely * to give a wrong result. * * Autobaud is primarily intended as a replacement for getty(8), and as such * it also sets a few terminal parameters such as the kill character to * default values. However, it can also be run from a shell for testing. * * usage: autobaud [-l] [ttyname] * * -l sets "login" mode and execs login after the speed is set * ttyname specifies a device to autobaud (/dev/ttyname) instead of stdin * * Gregg Townsend * University of Arizona * April, 1987 */ #define PGMNAME "autobaud" /* program name (for diagnostics) */ #define LOGIN "/bin/login" /* location of login program */ #define STRSIZ 100 /* string size for host and tty names */ #include <sgtty.h> #include <signal.h> #include <stdio.h> #include <sys/file.h> #include <sys/time.h> char *sp[] = { "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", "1800", "2400", "4800", "9600", "EXTA", "EXTB"}; int login = 0; /* set nonzero if to exec login */ char ttyname[STRSIZ] = "/dev/"; /* buffer for explicit tty name */ char hostname[STRSIZ]; /* buffer for hostname */ /* main program */ main(argc,argv) int argc; char **argv; { struct sgttyb ttyb; unsigned char c; char s; int zero = 0; argv++; /* skip program name */ if (*argv && !strcmp(*argv,"-l")) login++, argv++; /* if "-l", set login flag */ if (*argv) { strcpy(ttyname+5,*argv++); /* if tty given, build name */ close(0); /* close previous stdin */ close(1); /* close previous stdout */ close(2); /* close previous stderr */ if (login) { nap(2000); /* hold DTR down for 2 sec */ chown(ttyname,0,0); /* make root the owner */ chmod(ttyname,0622); /* and set the protections */ } if (open(ttyname,O_RDWR) != 0) /* open once for stdin */ abort(ttyname); dup(0); /* dup for stdout */ dup(0); /* dup for stderr */ } ttyb.sg_ispeed = ttyb.sg_ospeed = B2400; /* sample line at 2400 baud */ ttyb.sg_erase = ttyb.sg_kill = -1; /* no editing characters */ ttyb.sg_flags = EVENP + ODDP + RAW; /* raw mode, no echo */ if (ioctl(0,TIOCSETN,&ttyb) <0) /* set tty parameters */ abort("ioctl"); s = 0; while (!s) { nap(100); /* wait .1 sec for line quiet */ ioctl(0,TIOCFLUSH,&zero); /* flush input & output */ if (read(0,&c,1) != 1) /* read a character */ exit(1); /* select baud rate based on pattern received */ if (c >= 0xF0) s = B9600; else switch (c) { case 0x80: s = B300; break; case 0x78: s = B600; break; case 0xE6: s = B1200; break; case 0x0D: s = B2400; break; case 0x8D: s = B2400; break; default: s = 0; break; } } nap(100); /* let slow input finish */ ttyb.sg_ispeed = ttyb.sg_ospeed = s; /* set speeds */ ttyb.sg_erase = '\b'; /* \b for char correction */ ttyb.sg_kill = 'U' & 037; /* ^U for line kill */ ttyb.sg_flags = XTABS+EVENP+ODDP+CRMOD+ECHO;/* any parity, -TABS, CR, ECHO*/ ioctl(0,TIOCSETN,&ttyb); /* set parameters */ ioctl(0,TIOCFLUSH,&zero); /* flush I/O */ ioctl(0,TIOCHPCL,0); /* set hangup on last close */ if (login) { gethostname(hostname,STRSIZ); printf("\n%s %s\n",hostname,ttyname+5); /* display banner */ fflush(stdout); /* flush it */ execl(LOGIN,"login",NULL); /* exec login */ abort("can't exec login"); } else { printf("%s baud\n",sp[s]); /* from shell,just print speed*/ exit(0); } } /* abort(s) - abort, for reason given in string s, calling perror first * * (It's not totally clear what we should do, but we'll do it here for * uniformity.) */ abort(s) char *s; { fprintf(stderr,"%s: ",PGMNAME); /* display program name */ perror(s); /* display detail, and error message */ if (login) nap(5000); /* prevent fast looping in login mode */ exit(1); } /* nap(n) - delay for n milliseconds. * Assumes nobody else is using SIGALRM or ITIMER_REAL. */ static int nap_flag = -1; static nap_done() { nap_flag = 0; } nap(n) int n; { struct itimerval t; if (nap_flag < 0) signal(SIGALRM,nap_done); if (!(nap_flag = n)) return; t.it_value.tv_sec = n / 1000; t.it_value.tv_usec = (n % 1000) * 1000; t.it_interval.tv_sec = t.it_interval.tv_usec = 0; setitimer(ITIMER_REAL,&t,(struct itimerval *)0); while (nap_flag) pause(); } AlBeRtEiNsTeIn exit 0 -- For comp.sources.unix stuff, mail to sources@uunet.uu.net.