home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume3 / dialout < prev    next >
Internet Message Format  |  1986-11-30  |  37KB

  1. From: Chris Torek <talcott!mimsy.umd.edu:gymble!chris>
  2. Subject: dial-out mods for 4.3BSD
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 3, Issue 71
  7. Submitted by: Chris Torek <seismo!umcp-cs!chris>
  8.  
  9. [ I don't have BSD 4.3, so have not been able to check this out -  moderator ]
  10.  
  11. : Run this shell script with "sh" not "csh"
  12. PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
  13. export PATH
  14. all=FALSE
  15. if [ x$1 = x-a ]; then
  16.     all=TRUE
  17. fi
  18. echo 'Extracting README'
  19. sed 's/^X//' <<'//go.sysin dd *' >README
  20.             4.3BSD DIALOUT MODS
  21.             -------------------
  22.  
  23.     N.B.:  These changes should work for 4.2BSD as well; but
  24.     the `original' code shown in the diff listings will not
  25.     quite match.  You will have to install the changes by
  26.     hand---`patch' will not work.
  27.  
  28. Installation instructions for the dial devices:
  29.  
  30. 1.  Save copies of the files you will edit.  These include vax/conf.c
  31.     and at least one of the device drivers in vaxuba (vaxuba/dh.c,
  32.     vaxuba/dz.c, etc.)
  33.  
  34. 2.  Apply the changes shown to the device driver(s).  For other
  35.     devices you will need to extrapolate the changes.  Look at dh.c
  36.     and dz.c to see what needs to be done, and read the `dial
  37.     device' document.
  38.     
  39.     N.B.:  For dmf32s the changes can be rather tricky.  I have a
  40.     dmf32 driver that does dial out, but it is not the standard
  41.     4.3BSD version, so I cannot make diff listings.
  42.  
  43. 3.  Add the device(s) to the `cdevsw' table in vax/conf.c.  The
  44.     diff listing included here is heavily edited and should be used
  45.     only as an example.  You will need to assign major device
  46.     numbers yourself.  We used 41 and 42 for the dz and dh
  47.     respectively; but the first number free in the distributed
  48.     kernel is much lower---near 25, as I recall.
  49.  
  50. 4.  Compile a new kernel, and reboot.
  51.  
  52. 5.  Make `/dev' entries for the dial devices.  (See the `dial device'
  53.     document.)
  54.  
  55. 6.  Test.  Included is a C program that can talk to dial lines.
  56.     The program may need slight changes for 4.2BSD, though I think
  57.     I have removed most system dependencies already.  (You will,
  58.     however, need `getopt'.)
  59.  
  60.  
  61.         May the stars shine upon your kernel for ever,
  62.                         Chris Torek
  63.                         University of Maryland
  64.                         22 December 1983
  65. //go.sysin dd *
  66. if [ `wc -c < README` != 1700 ]; then
  67.     made=FALSE
  68.     echo 'error transmitting "README" --'
  69.     echo 'length should be 1700, not' `wc -c < README`
  70. else
  71.     made=TRUE
  72. fi
  73. if [ $made = TRUE ]; then
  74.     chmod 644 README
  75.     echo -n '    '; ls -ld README
  76. fi
  77. echo 'Extracting c.1'
  78. sed 's/^X//' <<'//go.sysin dd *' >c.1
  79. X.TH C 1
  80. X.UC 4
  81. X.SH NAME
  82. c \- communications program
  83. X.SH SYNOPSIS
  84. X.B "c -l"
  85. X.I link
  86. [
  87. X.B -s
  88. X.I speed
  89. ] [
  90. X.B -p
  91. X.I parity
  92. ] [
  93. X.B -e
  94. X.I escape
  95. ]
  96. X.SH DESCRIPTION
  97. X.I C
  98. is a small communications program for tty lines.  It has almost
  99. no features, unlike
  100. X.IR tip ,
  101. so it starts and runs quickly and is very small.  It is also useful
  102. for talking to balky modems when all other methods fail.
  103. X.PP
  104. The
  105. X.I link
  106. option is required, and should be the name of the tty line, e.g.,
  107. `/dev/dial05' or `/dev/ttya'.
  108. X.PP
  109. The
  110. X.I speed
  111. option selects the baud rate.  It should be a numeric value from
  112. the set {300, 600, 1200, 2400, 4800, 9600}.  The default is 1200
  113. baud.
  114. X.PP
  115. The
  116. X.I parity
  117. switch selects parity, which may be any of the following:
  118. X.TP
  119. X.B e
  120. Even parity
  121. X.TP
  122. X.B o
  123. Odd parity
  124. X.TP
  125. X.B 1
  126. One parity
  127. X.TP
  128. X.B 0
  129. Zero parity
  130. X.TP
  131. X.B n
  132. No parity (the data path is eight bits wide\(emthis is the default).
  133. X.PP
  134. The
  135. X.I esc
  136. parameter sets the escape character (default ESC).  This
  137. character must be doubled to be sent through the link.  Also
  138. available are the following `escape commands':
  139. X.TP
  140. X.B b
  141. Generate a break.
  142. X.TP
  143. X.B h, ?
  144. Help (list these options).
  145. X.TP
  146. X.B o
  147. Set options.  The program will prompt for an option line
  148. on which any of the flags except
  149. X.B -l
  150. may be changed.  Options are given in the same way
  151. as when the program is initially run.
  152. X.TP
  153. X.B q
  154. Quit (exit the program).  The program will quit by itself
  155. if carrier is lost, though this depends on the kernel configuration.
  156. X.TP
  157. X.B z
  158. Suspend.
  159. X.PP
  160. Other characters cause the bell to ring.
  161. X.SH SEE ALSO
  162. tip(1), cu(1)
  163. X.SH AUTHOR
  164. Chris Torek (seismo!umcp-cs!chris, chris@mimsy.umd.edu)
  165. X.SH BUGS
  166. Parity only affects outgoing characters.  Incoming data is
  167. always turned into zero parity.
  168. //go.sysin dd *
  169. if [ `wc -c < c.1` != 1715 ]; then
  170.     made=FALSE
  171.     echo 'error transmitting "c.1" --'
  172.     echo 'length should be 1715, not' `wc -c < c.1`
  173. else
  174.     made=TRUE
  175. fi
  176. if [ $made = TRUE ]; then
  177.     chmod 644 c.1
  178.     echo -n '    '; ls -ld c.1
  179. fi
  180. echo 'Extracting c.c'
  181. sed 's/^X//' <<'//go.sysin dd *' >c.c
  182. #ifndef lint
  183. static char rcsid[] = "$Header$";
  184. #endif
  185.  
  186. #include <stdio.h>
  187. #include <signal.h>
  188. #include <sys/types.h>
  189. #include <sys/file.h>
  190. #include <sgtty.h>
  191. #ifdef lint
  192. #include <sys/time.h>
  193. #endif
  194.  
  195. X/*
  196.  * Usage: c -l link [ -s speed ] [ -p e|o|0|1|n ] [ -e escapechar ]
  197.  *
  198.  * Comm program.
  199.  *
  200.  * Compilation:
  201.  % cc -O -R -o c c.c
  202.  *
  203.  * N.B.:  Should be setuid root, so that it can run at high priority
  204.  * (helps avoid losing input at high baud rates).
  205.  */
  206.  
  207. #ifndef lint
  208. extern    int    errno;
  209. extern    char    *optarg;
  210. extern    int    optind;
  211. #else
  212. int    errno;
  213. char    *optarg;
  214. int    optind;
  215. X/* VARARGS3 ARGSUSED */
  216. error(quit, e, fmt) int quit, e; char *fmt; { ; }
  217. #endif
  218.  
  219. char    *_argv0;
  220. char    *linkname;
  221. int    linkfd;
  222. int    speed;
  223. int    escchar;
  224. int    parbis;
  225. int    parbic;
  226. char    *partab;
  227. char    ttybuf[BUFSIZ];
  228. int    ttycount;
  229. char    ttyobuf[BUFSIZ];
  230. int    ttyocount;
  231. char    linebuf[BUFSIZ];
  232. int    linecount;
  233. char    lineobuf[BUFSIZ];
  234. int    lineocount;
  235.  
  236. X/*
  237.  * 4.3 and V8 style file descriptor mask macros
  238.  * Should be in <sys/types.h> but aren't in 4.2.
  239.  */
  240. #ifndef FD_SET
  241. typedef struct fd_set {
  242.     int    fds_bits;
  243. } fd_set;
  244. #define    FD_SET(n, p)    ((p)->fds_bits[0] |= (1 << (n)))
  245. #define    FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1 << (n)))
  246. #define    FD_ISSET(n, p)    ((p)->fds_bits[0] & (1 << (n)))
  247. #define    FD_ZERO(p)    ((p)->fds_bits = 0)
  248. #endif
  249.  
  250. char    evenpar[128] = {
  251.     0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x06, 0x87,
  252.     0x88, 0x09, 0x0a, 0x8b, 0x0c, 0x8d, 0x8e, 0x0f,
  253.     0x90, 0x11, 0x12, 0x93, 0x14, 0x95, 0x96, 0x17,
  254.     0x18, 0x99, 0x9a, 0x1b, 0x9c, 0x1d, 0x1e, 0x9f,
  255.     0xa0, 0x21, 0x22, 0xa3, 0x24, 0xa5, 0xa6, 0x27,
  256.     0x28, 0xa9, 0xaa, 0x2b, 0xac, 0x2d, 0x2e, 0xaf,
  257.     0x30, 0xb1, 0xb2, 0x33, 0xb4, 0x35, 0x36, 0xb7,
  258.     0xb8, 0x39, 0x3a, 0xbb, 0x3c, 0xbd, 0xbe, 0x3f,
  259.     0xc0, 0x41, 0x42, 0xc3, 0x44, 0xc5, 0xc6, 0x47,
  260.     0x48, 0xc9, 0xca, 0x4b, 0xcc, 0x4d, 0x4e, 0xcf,
  261.     0x50, 0xd1, 0xd2, 0x53, 0xd4, 0x55, 0x56, 0xd7,
  262.     0xd8, 0x59, 0x5a, 0xdb, 0x5c, 0xdd, 0xde, 0x5f,
  263.     0x60, 0xe1, 0xe2, 0x63, 0xe4, 0x65, 0x66, 0xe7,
  264.     0xe8, 0x69, 0x6a, 0xeb, 0x6c, 0xed, 0xee, 0x6f,
  265.     0xf0, 0x71, 0x72, 0xf3, 0x74, 0xf5, 0xf6, 0x77,
  266.     0x78, 0xf9, 0xfa, 0x7b, 0xfc, 0x7d, 0x7e, 0xff,
  267. };
  268. char    oddpar[128] = {
  269.     0x80, 0x01, 0x02, 0x83, 0x04, 0x85, 0x86, 0x07,
  270.     0x08, 0x89, 0x8a, 0x0b, 0x8c, 0x0d, 0x0e, 0x8f,
  271.     0x10, 0x91, 0x92, 0x13, 0x94, 0x15, 0x16, 0x97,
  272.     0x98, 0x19, 0x1a, 0x9b, 0x1c, 0x9d, 0x9e, 0x1f,
  273.     0x20, 0xa1, 0xa2, 0x23, 0xa4, 0x25, 0x26, 0xa7,
  274.     0xa8, 0x29, 0x2a, 0xab, 0x2c, 0xad, 0xae, 0x2f,
  275.     0xb0, 0x31, 0x32, 0xb3, 0x34, 0xb5, 0xb6, 0x37,
  276.     0x38, 0xb9, 0xba, 0x3b, 0xbc, 0x3d, 0x3e, 0xbf,
  277.     0x40, 0xc1, 0xc2, 0x43, 0xc4, 0x45, 0x46, 0xc7,
  278.     0xc8, 0x49, 0x4a, 0xcb, 0x4c, 0xcd, 0xce, 0x4f,
  279.     0xd0, 0x51, 0x52, 0xd3, 0x54, 0xd5, 0xd6, 0x57,
  280.     0x58, 0xd9, 0xda, 0x5b, 0xdc, 0x5d, 0x5e, 0xdf,
  281.     0xe0, 0x61, 0x62, 0xe3, 0x64, 0xe5, 0xe6, 0x67,
  282.     0x68, 0xe9, 0xea, 0x6b, 0xec, 0x6d, 0x6e, 0xef,
  283.     0x70, 0xf1, 0xf2, 0x73, 0xf4, 0x75, 0x76, 0xf7,
  284.     0xf8, 0x79, 0x7a, 0xfb, 0x7c, 0xfd, 0xfe, 0x7f,
  285. };
  286.  
  287. struct    sgttyb sgbuf;
  288.  
  289. main(argc, argv)
  290.     int argc;
  291.     char **argv;
  292. {
  293.     register int fd, c, tx, lx;
  294.     static int state;
  295.  
  296.     _argv0 = argv[0];
  297.  
  298.     speed = B1200;
  299.     escchar = 27;
  300.     argue(argc, argv, 1);
  301.  
  302.     (void) nice(-10);
  303.     (void) setuid(getuid());
  304.  
  305.     fd = open(linkname, O_RDWR, 0);
  306.     if (fd < 0)
  307.         error(1, errno, "can't open %s", linkname);
  308.  
  309.     linkfd = fd;
  310.     fixlink();
  311.     rawtty();
  312.     printf("open\r\n");
  313.     lx = 0;
  314.     tx = 0;
  315.  
  316.     for (;;) {
  317.         if (lx >= linecount && tx >= ttycount) {
  318.             fd_set inbits;
  319.  
  320.             if (ttyocount)
  321.                 flusho(ttyobuf, &ttyocount, 1);
  322.             if (lineocount)
  323.                 flusho(lineobuf, &lineocount, fd);
  324.  
  325.             /* read from tty and/or line */
  326.             FD_ZERO(&inbits);
  327.             FD_SET(1, &inbits);
  328.             FD_SET(fd, &inbits);
  329.             c = select(fd + 1, &inbits, (fd_set *) 0, (fd_set *) 0,
  330.                    (struct timeval *) 0);
  331.             if (c == 0) {
  332.                 error(0, errno, "select");
  333.                 cleanup(1);
  334.             }
  335.             if (FD_ISSET(1, &inbits)) {
  336.                 ttycount = read(0, ttybuf, BUFSIZ);
  337.                 if (ttycount < 0) {
  338.                     error(0, errno, "read(0)");
  339.                     cleanup(1);
  340.                 }
  341.                 if (ttycount == 0) {
  342.                     error(0, 0, "eof(0)?");
  343.                     cleanup(1);
  344.                 }
  345.                 tx = 0;
  346.             }
  347.             if (FD_ISSET(fd, &inbits)) {
  348.                 linecount = read(fd, linebuf, BUFSIZ);
  349.                 if (linecount < 0) {
  350.                     error(0, errno, "read(%d)", fd);
  351.                     cleanup(1);
  352.                 }
  353.                 if (linecount == 0) {
  354.                     error(0, 0, "eof(%d)?", fd);
  355.                     cleanup(1);
  356.                 }
  357.                 lx = 0;
  358.             }
  359.         }
  360.         /* handle tty input */
  361.         while (tx < ttycount) {
  362.             c = ttybuf[tx++] & 0x7f;
  363.             if (state) {
  364.                 state = 0;
  365.                 if (c == escchar)
  366.                     goto put;
  367.                 switch (c) {
  368.                 case 'b':
  369.                     genbreak();
  370.                     break;
  371.  
  372.                 case 'q':
  373.                     cleanup(0);
  374.                     /*NOTREACHED*/
  375.  
  376.                 case 'z':
  377.                     printf("\r\nsuspend\r\n");
  378.                     susp();
  379.                     printf("resumed\r\n");
  380.                     break;
  381.  
  382.                 case 'h':
  383.                 case 'H':
  384.                 case '?':
  385.                     printf("\r\n\
  386. ESC subcommands:\r\n\
  387.     b - generate a break\r\n\
  388.     o - set options\r\n\
  389.     q - quit\r\n\
  390.     z - suspend\r\n");
  391.                     break;
  392.  
  393.                 case 'o':
  394.                 case 'O':
  395.                     options();
  396.                     break;
  397.  
  398.                 default:
  399. beep:
  400.                     ttyobuf[ttyocount++] = 7;
  401.                     if (ttyocount == BUFSIZ)
  402.                         flusho(ttyobuf, &ttyocount, 1);
  403.                     break;
  404.                 }
  405.             } else if (c == escchar) {
  406.                 state = 1;
  407.                 goto beep;
  408.             } else {
  409. put:
  410.                 if (partab)
  411.                     c = partab[c];
  412.                 else    /* restore parity */
  413.                     c = ttybuf[tx - 1];
  414.                 c |= parbis;
  415.                 c &= ~parbic;
  416.                 lineobuf[lineocount++] = c;
  417.                 if (lineocount == BUFSIZ)
  418.                     flusho(lineobuf, &lineocount, fd);
  419.             }
  420.         }
  421.         /* handle line input */
  422.         while (lx < linecount) {
  423.             c = linebuf[lx++];
  424.             /* handle parity here someday */
  425.             ttyobuf[ttyocount++] = c & 0x7f;
  426.             if (ttyocount == BUFSIZ)
  427.                 flusho(ttyobuf, &ttyocount, fd);
  428.         }
  429.     }
  430. }
  431.  
  432. flusho(buf, p, fd)
  433.     char *buf;
  434.     register int *p;
  435.     int fd;
  436. {
  437.  
  438.     if (write(fd, buf, *p) != *p) {
  439.         error(0, errno, "write(%d)", fd);
  440.         cleanup(1);
  441.     }
  442.     *p = 0;
  443. }
  444.  
  445. cleanup(code)
  446.     int code;
  447. {
  448.  
  449.     printf("\r\nclosed\r\n");
  450.     (void) ioctl(0, TIOCSETP, &sgbuf);
  451.     exit(code);
  452. }
  453.  
  454. rawtty()
  455. {
  456.     struct sgttyb raw;
  457.  
  458.     if (ioctl(0, TIOCGETP, &sgbuf))
  459.         error(1, errno, "ioctl TIOCGETP");
  460.     raw = sgbuf;
  461.     raw.sg_flags = RAW;
  462.     (void) ioctl(0, TIOCSETP, &raw);
  463. }
  464.  
  465. susp()
  466. {
  467.  
  468.     (void) ioctl(0, TIOCSETP, &sgbuf);
  469.     kill(0, SIGTSTP);
  470.     rawtty();
  471. }
  472.  
  473. struct speeds {
  474.     int sp;
  475.     int sp_b;
  476. };
  477.  
  478. findspeed(sp)
  479. {
  480.     register struct speeds *spp;
  481.     static struct speeds speeds[] = {
  482.         300, B300, 600, B600, 1200, B1200, 2400, B2400,
  483.         4800, B4800, 9600, B9600, -1, -1
  484.     };
  485.  
  486.     spp = speeds;
  487.     while (spp->sp >= 0) {
  488.         if (spp->sp == sp)
  489.             return (spp->sp_b);
  490.         spp++;
  491.     }
  492.     return (-1);
  493. }
  494.  
  495. genbreak()
  496. {
  497.  
  498.     (void) ioctl(linkfd, TIOCSBRK, 0);
  499.     sleep(1);
  500.     (void) ioctl(linkfd, TIOCCBRK, 0);
  501. }
  502.  
  503. char **
  504. makeargv(avp, s)
  505.     register char **avp, *s;
  506. {
  507.  
  508.     for (;;) {
  509.         while (*s == ' ' || *s == '\t' || *s == '\n')
  510.             s++;
  511.         if (*s == 0) {
  512.             *avp = 0;
  513.             return avp;
  514.         }
  515.         *avp++ = s;
  516.         while (*s && *s != ' ' && *s != '\t' && *s != '\n')
  517.             s++;
  518.         if (*s == 0) {
  519.             *avp = 0;
  520.             return avp;
  521.         }
  522.         *s++ = 0;
  523.     }
  524. }
  525.  
  526. options()
  527. {
  528.     char buf[200];
  529.     char *argv[100];
  530.     int argc;
  531.  
  532.     (void) ioctl(0, TIOCSETP, &sgbuf);
  533.     printf("options: ");
  534.     if (fgets(buf, sizeof buf, stdin) == NULL)
  535.         exit(1);
  536.     argv[0] = _argv0;
  537.     argc = makeargv(argv + 1, buf) - argv;
  538.     argue(argc, argv, 0);
  539.     rawtty();
  540. }
  541.  
  542. argue(argc, argv, toplevel)
  543.     int argc;
  544.     char **argv;
  545.     int toplevel;
  546. {
  547.     register int c;
  548.  
  549.     optind = 1;
  550.     while ((c = getopt(argc, argv, "s:p:l:e:")) != EOF) {
  551.         switch (c) {
  552.         case '?':
  553. usage:
  554.             if (toplevel) {
  555.                 error(1, 0, "\
  556. usage: c -l link [-s speed] [-p par] [-e esc]");
  557.                 /* NOTREACHED */
  558.             }
  559.             error(0, 0, "options: [-s speed] [-p par] [-e esc]");
  560.             break;
  561.  
  562.         case 'l':
  563.             if (!toplevel) {
  564.                 error(0, 0, "can't change link in midstream");
  565.                 break;
  566.             }
  567.             if (linkname)
  568.                 error(1, 0, "use only one -l option");
  569.             linkname = optarg;
  570.             break;
  571.  
  572.         case 's':
  573.             if ((speed = findspeed(atoi(optarg))) < 0)
  574.                 error(toplevel, 0, "invalid speed %s", optarg);
  575.             if (!toplevel)
  576.                 fixlink();
  577.             break;
  578.  
  579.         case 'p':
  580.             if (*optarg == 'e') {
  581.                 partab = evenpar;
  582.                 parbis = parbic = 0;
  583.             } else if (*optarg == 'o') {
  584.                 partab = oddpar;
  585.                 parbis = parbic = 0;
  586.             } else if (*optarg == '1') {
  587.                 parbis = 0x80;
  588.                 parbic = 0;
  589.             } else if (*optarg == '0') {
  590.                 parbis = 0;
  591.                 parbic = 0x80;
  592.             } else if (*optarg == 'n') {
  593.                 parbis = parbic = 0;
  594.                 partab = 0;
  595.             } else
  596.                 error(toplevel, 0, "\
  597. for -p, use one of [e, o, 1, 0, n]");
  598.             break;
  599.  
  600.         case 'e':
  601.             if (optarg[1] == 0)
  602.                 escchar = *optarg;
  603.             else if (optarg[0] == '^')
  604.                 escchar = optarg[1] == '?' ? 0x7f :
  605.                       *optarg & 0x1f;
  606.             else
  607.                 escchar = atoi(optarg);
  608.             printf("escape set to %s%c.\n",
  609.                    escchar >= 0x20 && escchar < 0x7f ? "" : "^",
  610.             escchar >= 0x20 ? (escchar == 0x7f ? '?' : escchar) :
  611.                    escchar + '@');
  612.             break;
  613.         default:
  614.             error(1, 0, "internal error: argue switch");
  615.         }
  616.     }
  617.     if (linkname == 0)
  618.         goto usage;
  619. }
  620.  
  621. fixlink()
  622. {
  623.     struct sgttyb l;
  624.  
  625.     l.sg_ispeed = l.sg_ospeed = speed;
  626.     l.sg_flags = RAW;
  627.     (void) ioctl(linkfd, TIOCSETN, &l);
  628. }
  629.  
  630. #ifndef lint
  631. X/*
  632.  * Error routine from the local C library
  633.  * N.B.: This code is system dependent.
  634.  */
  635.  
  636. X/*
  637.  * error - University of Maryland specific (sigh)
  638.  *
  639.  * Useful for printing error messages.  Will print the program name
  640.  * and (optionally) the system error associated with the values in
  641.  * <errno.h>.
  642.  *
  643.  * Note that the type (and even the existence!) of ``arg'' is undefined.
  644.  */
  645. error(quit, e, fmt, arg)
  646.     int quit;
  647.     register int e;
  648.     char *fmt;
  649. {
  650.     extern char *sys_errlist[];
  651.     extern int sys_nerr;
  652.     register char *p = _argv0;
  653.  
  654.     if (p != NULL)
  655.         (void) fprintf(stderr, "%s: ", p);
  656.     _doprnt(fmt, &arg, stderr);    /* magic */
  657.     if (e > 0) {
  658.         if (e < sys_nerr)
  659.             (void) fprintf(stderr, ": %s", sys_errlist[e]);
  660.         else
  661.             (void) fprintf(stderr, ": unknown error number %d", e);
  662.     }
  663.     (void) putc('\n', stderr);
  664.     (void) fflush(stderr);
  665.     if (quit)
  666.         exit(quit);
  667. }
  668. #endif
  669. //go.sysin dd *
  670. if [ `wc -c < c.c` != 9712 ]; then
  671.     made=FALSE
  672.     echo 'error transmitting "c.c" --'
  673.     echo 'length should be 9712, not' `wc -c < c.c`
  674. else
  675.     made=TRUE
  676. fi
  677. if [ $made = TRUE ]; then
  678.     chmod 644 c.c
  679.     echo -n '    '; ls -ld c.c
  680. fi
  681. echo 'Extracting dial.tex'
  682. sed 's/^X//' <<'//go.sysin dd *' >dial.tex
  683. %
  684. % dial.tex - some notes on the implementation of simultaneous dial in/out
  685. % on modem lines.
  686. %
  687.  
  688. % 11 pt
  689. \magnification=\magstephalf
  690.  
  691. % Fonts.  If you are using TeX78, or the new Computer Modern fonts, change
  692. % this to cmcsc10.
  693. \font\tencsc=amcsc10
  694.  
  695. % Macros
  696. \newif\iftm    % true if we have mentioned the trademark
  697. \def\Unix{{\tencsc Unix}\iftm\else\footnote{$\dag$}{{\tencsc Unix} is a
  698. footnote of AT\&T Bell Laboratories}\global\tmtrue\fi}
  699. \def\bsd{{\tencsc 4.3bsd} \Unix}
  700. % \tencsc does not look very good on these, so we will use regular fonts.
  701. %\def\dec{{\tencsc dec}}
  702. %\def\dz{{\tencsc dz11}}    % official version
  703. %\def\dzz{{\tencsc dz}}        % short version, purely for variety
  704. %\def\dh{{\tencsc dh11}}
  705. \def\dec{{\rm DEC}}
  706. \def\dz{{\rm DZ11}}
  707. \def\dzz{{\rm DZ}}
  708. \def\dh{{\rm DH11}}
  709. \chardef\us=`\_
  710.  
  711. % Layout
  712. \parskip=.5\baselineskip plus1pt
  713. \footline={\ifnum\pageno=1\hfil\else{\tenrm\hfil Dial Devices for
  714. \bsd\hfil\llap{\folio}}\fi}
  715.  
  716. % Here we go...
  717.  
  718. % Header, plus page 1 (save paper)
  719. % How about THIS title!  Catchy, no?
  720. \null
  721. \vskip1cm
  722. \centerline{Some Notes on the Implementation of Dialout Capabilites}
  723. \centerline{for Modem Lines under \bsd}
  724. \vskip.5cm
  725. \centerline{Chris Torek}
  726. \vskip.5cm
  727. \centerline{Department of Computer Science}
  728. \centerline{University of Maryland}
  729. \centerline{College Park, MD 20742}
  730.  
  731. \vskip 2cm
  732.  
  733. % Ok.  Now what?
  734. % How about this:
  735.  
  736. Modern modems may be used in both `originate' and `answer' modes---that
  737. is, they can both call out and answer incoming calls.  Traditional
  738. \Unix\ systems, however, cannot handle this well; modems have
  739. typically been dedicated to one purpose or the other.  At the
  740. University of Maryland, we have devised a set of kernel modifications
  741. that allow modem lines to be used bidirectionally.  These present
  742. a simple user interface and require none of the error-prone locking
  743. protocols that have been used in the past to implement similar
  744. functionality.  Moreover, using our scheme, site administrators
  745. can if they so choose implement accounting for all outgoing calls.
  746. Previous systems rendered this difficult at best.
  747.  
  748. % Enough extolling of virtues.  Now for some details:
  749.  
  750. As far as user programs are concerned, the only change to the system
  751. is the addition of a new set of {\it dial} devices.  These devices
  752. have a one-to-one correspondence with the {\it tty} lines; they
  753. are distinguished by having a different major device number.  For
  754. example, on one machine we have two Racal-Vadic
  755. VA3400\footnote{$\ddag$}{Vadic and VA3400 are no doubt trademarks
  756. of someone or another} modems.  These appear as {\tt tty04} and {\tt
  757. tty05}, and also as {\tt dial04} and {\tt dial05}:
  758.  
  759. {\tt\vskip\parskip\parskip=0pt\obeylines\obeyspaces%
  760. crw--w--w-  1 root       1,   4 Dec  3 00:06 /dev/tty04
  761. crw--w--w-  1 root       1,   5 Dec  2 00:27 /dev/tty05
  762. crw-rw-rw-  1 root      41,   4 Dec  2 23:13 /dev/dial04
  763. crw-rw-rw-  1 root      41,   5 Dec  2 23:16 /dev/dial05
  764.  
  765. } % what, me, work late?        ^^^
  766.  
  767. Here major device 1 corresponds to the \dec\ \dz.\footnote{*}{\dec,
  768. \dh, and \dz\ are trademarks of Digital Equipment Corporation}
  769. Major device 41 is also the \dz, but in `dial out' or `outgoing'
  770. mode.  When a program opens the normal or `incoming' line, it
  771. behaves as such programs always have:  If there is a carrier on
  772. the line, the open completes normally; if not, the open
  773. `hangs'---suspends---waiting for a carrier.  When a program opens
  774. the `outgoing' line, however, something new occurs.  If there is
  775. a carrier on the line, that indicates that the device is already
  776. in use; and the open is rejected with a `Device busy' error, {\tt
  777. EBUSY}.  (In previous versions of \Unix\ this was called a `Mount
  778. device busy' error.)  The open is likewise rejected if the line is
  779. already in use outgoing.  Indeed, in such cases there is always a
  780. carrier, so no additional code is required for this:  Only if there
  781. is no carrier does the open complete---and it will hang up
  782. automatically once a carrier has appeared and then vanished.
  783.  
  784. What happens, then, when a line is in the process of being opened
  785. for incoming use when the outgoing call is made?  Why, nothing, of
  786. course:  the incoming open remains suspended until the outgoing
  787. call has been completed.  Anything else would break existing code.
  788. As a bonus, no locking is required; outgoing opens succeed if and
  789. only if the line is not in use, and incoming opens remain hung
  790. during outgoing calls.
  791.  
  792. % Finally, the nitty-gritty; the details; the real guts of the game.
  793.  
  794. To illustrate how this is accomplished, I shall refer again to the
  795. \dz\ driver.  We have added two new arrays, and made use of an
  796. existing third array:  There is now a {\tt dz\us inout} and a {\tt
  797. dz\us flags}, both of size {\tt NDZ} and type {\tt char}.  The first
  798. holds the `outgoing mode' flag for each \dzz\ line.  Bit $b$ is set
  799. in {\tt dz\us inout[$d\/$]} whenever line $b$ of \dzz\ $d$ has an outgoing
  800. open in progress.  {\tt dz\us flags} holds a permanent copy of the
  801. `flags' parameter from the kernel configuration file.  In this case
  802. these are the software carrier flags.  In the original kernel these
  803. were put into the array {\tt dz\us softCAR}---also of size {\tt
  804. NDZ}---and never touched.  We must save them somewhere as outgoing
  805. opens work by temporarily asserting the software carrier.
  806.  
  807. We modified the device open code to return {\tt EBUSY} not only on
  808. attempts to open a line in `exclusive use' mode, but also on attempts
  809. to open a line in outgoing mode whenever the line is already open
  810. in any mode.  As usual, the super-user is exempt from this restriction.
  811. We also modified the open code to:
  812.  
  813. \item {1)} assert the software carrier on outgoing opens;
  814.  
  815. \item {2)} hang until there is a carrier (or software carrier);
  816.  
  817. \item {3)} hang until the line is not in use outgoing, unless this is
  818. the outgoing call itself; and
  819.  
  820. \item {4)} reassert DTR every time the state of the line changes.
  821.  
  822. \noindent
  823. Incoming and outgoing opens are distinguished by the `flag' argument
  824. to the device open routine.  This is always a small nonnegative
  825. integer for normal opens; but the outgoing open routine calls the
  826. regular open routine with a {\tt flag} of {\tt -1}.
  827.  
  828. The fourth point is important because of a change in the close
  829. routine.  To ensure that a modem hangs up, it is necessary to drop
  830. DTR for at least $1\over2$ second.  But modems will generally not
  831. answer the phone unless DTR is asserted.  So the close routine
  832. first drops DTR and maintains it that way for one second, then, if
  833. it is an outgoing close, turns off the outgoing mode flag, restores
  834. the software carrier, and awakens any hung incoming opens so that
  835. they may reassert DTR if necessary.  As with the open routine, an
  836. outgoing close is distinguished by its {\tt flag} argument.
  837.  
  838. We made one more change to the driver.  The modem interrupt code---or
  839. in the case of the \dz, the modem poll code, for there are no modem
  840. interrupts---now checks both the real carrier and the software
  841. carrier.  Either will allow the open to complete; but if the real
  842. carrier is asserted when the line is open in outgoing mode, the
  843. software carrier for that line is cleared.  This means that once
  844. an outgoing call completes, the line is usable only until the
  845. connection is closed:  When the carrier goes away, the line will
  846. be hung up, just as for a normal incoming open.  This allows one
  847. to perform call accounting, under the condition that the modem
  848. never allows calls to be placed without having first lost carrier;
  849. and this is true of most modems.  The dial-out program would be
  850. set-group-ID to a group that can open the `dial' devices.  This
  851. program would open the device, dial the number, wait for the call
  852. to complete, and then log the call in a file.  As long as the
  853. program were careful not to let the user set {\tt NOHUP} mode on
  854. the line, no further calls could be made, as the file descriptor
  855. would be invalidated and the program would be sent a {\tt SIGHUP}
  856. signal as soon as the connection were broken.
  857.  
  858. (We actually made another change to the \dzz\ driver.  {\tt MDMBUF}
  859. mode, wherein carrier transitions act as flow control, now works
  860. on \dz s as well as \dh s.  This is, however, of limited usefulness,
  861. as the \dzz\ modem status is only polled once every second; at 1200
  862. baud, up to 120 characters may be sent after a carrier drop before
  863. transmission is suspended, and at 9600 baud, up to 960 characters
  864. could conceivably be sent.  The lack of a modem interrupt is one of
  865. many problems with \dz s, and cannot truly be corrected in software.)
  866.  
  867. % Ok.  Summary:
  868.  
  869. These kernel changes have allowed us to make greater use, with more
  870. ease, of our existing dialer resources.  The automatic locking has
  871. eliminated all protocol errors that have plagued other systems in
  872. the past.  And we even log outgoing calls, though we do not charge
  873. for them or otherwise restrict them.
  874.  
  875. % clean up
  876.  
  877. \vskip.5cm
  878. \line{\it Acknowledgements\hfil}
  879.  
  880. Credit is due Joe Pallas, Bob Kirby, and Fred Blonder, who worked
  881. with me on our original implementation for V6 and 4.1{\tencsc bsd}
  882. \Unix.  This work was no doubt indirectly supported by several
  883. government grants and other misdirected research funds.  All the
  884. errors in this document, however, should be credited only to myself.
  885.  
  886. \bye
  887. //go.sysin dd *
  888. if [ `wc -c < dial.tex` != 9184 ]; then
  889.     made=FALSE
  890.     echo 'error transmitting "dial.tex" --'
  891.     echo 'length should be 9184, not' `wc -c < dial.tex`
  892. else
  893.     made=TRUE
  894. fi
  895. if [ $made = TRUE ]; then
  896.     chmod 644 dial.tex
  897.     echo -n '    '; ls -ld dial.tex
  898. fi
  899. echo 'Extracting diff.vax.conf.c'
  900. sed 's/^X//' <<'//go.sysin dd *' >diff.vax.conf.c
  901. RCS file: RCS/conf.c,v
  902. retrieving revision 1.1.1.2
  903. retrieving revision 1.5
  904. diff -c2 -r1.1.1.2 -r1.5  [edited]
  905. *** /tmp/,RCSt1000435    Mon Dec  2 23:47:17 1985
  906. --- /tmp/,RCSt2000435    Mon Dec  2 23:47:19 1985
  907. ***************
  908. *** 268,277 ****
  909. --- 301,3?? ----
  910.   #define    dhstop    nodev
  911.   #define    dhreset    nulldev
  912. + #define    dhoopen    nodev
  913. + #define    dhoclose nodev
  914.   #define    dh11    0
  915.   #else
  916.   int    dhopen(),dhclose(),dhread(),dhwrite(),dhioctl(),dhstop(),dhreset();
  917. + int    dhoopen(),dhoclose();
  918.   struct    tty dh11[];
  919.   #endif
  920. ***************
  921. *** 316,322 ****
  922. --- 375,384 ----
  923.   #define    dzstop    nodev
  924.   #define    dzreset    nulldev
  925. + #define    dzoopen    nodev
  926. + #define    dzoclose nodev
  927.   #define    dz_tty    0
  928.   #else
  929.   int    dzopen(),dzclose(),dzread(),dzwrite(),dzioctl(),dzstop(),dzreset();
  930. + int    dzoopen(),dzoclose();
  931.   struct    tty dz_tty[];
  932.   #endif
  933. ***************
  934. *** ???,??? ****
  935. --- ???,??? ----
  936. +     dzoopen,    dzoclose,    dzread,        dzwrite,    /*??*/
  937. +     dzioctl,    dzstop,        nulldev,    dz_tty,
  938. +     ttselect,    nodev,
  939. +     dhoopen,    dhoclose,    dhread,        dhwrite,    /*??*/
  940. +     dhioctl,    dhstop,        nulldev,    dh11,
  941. +     ttselect,    nodev,
  942. //go.sysin dd *
  943. if [ `wc -c < diff.vax.conf.c` != 1076 ]; then
  944.     made=FALSE
  945.     echo 'error transmitting "diff.vax.conf.c" --'
  946.     echo 'length should be 1076, not' `wc -c < diff.vax.conf.c`
  947. else
  948.     made=TRUE
  949. fi
  950. if [ $made = TRUE ]; then
  951.     chmod 644 diff.vax.conf.c
  952.     echo -n '    '; ls -ld diff.vax.conf.c
  953. fi
  954. echo 'Extracting diff.vaxuba.dh.c'
  955. sed 's/^X//' <<'//go.sysin dd *' >diff.vaxuba.dh.c
  956. RCS file: RCS/dh.c,v
  957. retrieving revision 1.1.1.3
  958. retrieving revision 1.4
  959. diff -c2 -r1.1.1.3 -r1.4
  960. *** /tmp/,RCSt1000424    Mon Dec  2 23:46:43 1985
  961. --- /tmp/,RCSt2000424    Mon Dec  2 23:46:45 1985
  962. ***************
  963. *** 70,73 ****
  964. --- 70,74 ----
  965.   short    dhsar[NDH];            /* software copy of last bar */
  966.   short    dhsoftCAR[NDH];
  967. + short    dh_inout[NDH];
  968.   
  969.   struct    tty dh11[NDH*16];
  970. ***************
  971. *** 80,84 ****
  972.   int    dhlowrate = 75;            /* silo off if dhrate < dhlowrate */
  973.   static short timerstarted;
  974. ! int    dhstart(), ttrstrt();
  975.   
  976.   /*
  977. --- 81,85 ----
  978.   int    dhlowrate = 75;            /* silo off if dhrate < dhlowrate */
  979.   static short timerstarted;
  980. ! int    dhstart(), ttrstrt(), wakeup();
  981.   
  982.   /*
  983. ***************
  984. *** 169,173 ****
  985.    * the first use of it.  Also do a dmopen to wait for carrier.
  986.    */
  987. - /*ARGSUSED*/
  988.   dhopen(dev, flag)
  989.       dev_t dev;
  990. --- 170,173 ----
  991. ***************
  992. *** 184,188 ****
  993.           return (ENXIO);
  994.       tp = &dh11[unit];
  995. !     if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
  996.           return (EBUSY);
  997.       addr = (struct dhdevice *)ui->ui_addr;
  998. --- 184,189 ----
  999.           return (ENXIO);
  1000.       tp = &dh11[unit];
  1001. !     if (u.u_uid != 0 && (tp->t_state&TS_XCLUDE ||
  1002. !         flag < 0 && tp->t_state&TS_ISOPEN))
  1003.           return (EBUSY);
  1004.       addr = (struct dhdevice *)ui->ui_addr;
  1005. ***************
  1006. *** 231,235 ****
  1007.        * Wait for carrier, then process line discipline specific open.
  1008.        */
  1009. !     dmopen(dev);
  1010.       return ((*linesw[tp->t_line].l_open)(dev, tp));
  1011.   }
  1012. --- 232,236 ----
  1013.        * Wait for carrier, then process line discipline specific open.
  1014.        */
  1015. !     dmopen(dev, flag);
  1016.       return ((*linesw[tp->t_line].l_open)(dev, tp));
  1017.   }
  1018. ***************
  1019. *** 236,242 ****
  1020.   
  1021.   /*
  1022. !  * Close a DH11 line, turning off the DM11.
  1023.    */
  1024.   /*ARGSUSED*/
  1025.   dhclose(dev, flag)
  1026.       dev_t dev;
  1027. --- 237,254 ----
  1028.   
  1029.   /*
  1030. !  * Outgoing mode open: fake the carrier.
  1031.    */
  1032.   /*ARGSUSED*/
  1033. + dhoopen(dev, flag)
  1034. +     dev_t dev;
  1035. +     int flag;
  1036. + {
  1037. +     return (dhopen(dev, -1));
  1038. + }
  1039. + /*
  1040. +  * Close a DH11 line, turning off the DM11.
  1041. +  */
  1042.   dhclose(dev, flag)
  1043.       dev_t dev;
  1044. ***************
  1045. *** 250,258 ****
  1046.       (*linesw[tp->t_line].l_close)(tp);
  1047.       ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
  1048. !     if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
  1049.           dmctl(unit, DML_OFF, DMSET);
  1050.       ttyclose(tp);
  1051.   }
  1052.   
  1053.   dhread(dev, uio)
  1054.       dev_t dev;
  1055. --- 262,290 ----
  1056.       (*linesw[tp->t_line].l_close)(tp);
  1057.       ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
  1058. !     if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0 || flag < 0) {
  1059.           dmctl(unit, DML_OFF, DMSET);
  1060. +         /* hold DTR low long enough for it to be detected */
  1061. +         timeout(wakeup, (caddr_t)&tp->t_state, hz);
  1062. +         sleep((caddr_t)&tp->t_state, TTOPRI);
  1063. +     }
  1064.       ttyclose(tp);
  1065. +     if (flag < 0) {        /* clear outgoing mode */
  1066. +         dh_inout[unit >> 4] &= ~(1 << (unit & 0xf));
  1067. +         wakeup((caddr_t)&tp->t_rawq);
  1068. +     }
  1069.   }
  1070.   
  1071. + /*
  1072. +  * Close an outgoing DH line
  1073. +  */
  1074. + /*ARGSUSED*/
  1075. + dhoclose(dev, flag)
  1076. +     dev_t dev;
  1077. +     int flag;
  1078. + {
  1079. +     dhclose(dev, -1);
  1080. + }
  1081.   dhread(dev, uio)
  1082.       dev_t dev;
  1083. ***************
  1084. *** 403,406 ****
  1085. --- 435,439 ----
  1086.           tp->t_state |= TS_HUPCLS;
  1087.           dmctl(unit, DML_OFF, DMSET);
  1088. +         splx(s);
  1089.           return;
  1090.       }
  1091. ***************
  1092. *** 671,676 ****
  1093.    * Turn on the line associated with dh dev.
  1094.    */
  1095. ! dmopen(dev)
  1096.       dev_t dev;
  1097.   {
  1098.       register struct tty *tp;
  1099. --- 704,710 ----
  1100.    * Turn on the line associated with dh dev.
  1101.    */
  1102. ! dmopen(dev, flag)
  1103.       dev_t dev;
  1104. +     int flag;
  1105.   {
  1106.       register struct tty *tp;
  1107. ***************
  1108. *** 685,689 ****
  1109.       tp = &dh11[unit];
  1110.       unit &= 0xf;
  1111. !     if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
  1112.           tp->t_state |= TS_CARR_ON;
  1113.           return;
  1114. --- 719,724 ----
  1115.       tp = &dh11[unit];
  1116.       unit &= 0xf;
  1117. !     if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
  1118. !         (dhsoftCAR[dm]&(1<<unit))) {
  1119.           tp->t_state |= TS_CARR_ON;
  1120.           return;
  1121. ***************
  1122. *** 691,694 ****
  1123. --- 726,754 ----
  1124.       addr = (struct dmdevice *)ui->ui_addr;
  1125.       s = spl5();
  1126. +     if (flag < 0) {
  1127. +         dh_inout[dm] |= 1 << unit;
  1128. +         dmassert(addr, dm, unit, tp);
  1129. +         tp->t_state |= TS_CARR_ON;
  1130. +     }
  1131. +     else {
  1132. +         do {
  1133. +             dmassert(addr, dm, unit, tp);
  1134. +             if (tp->t_state&TS_CARR_ON &&
  1135. +                 (dh_inout[dm]&(1<<unit)) == 0)
  1136. +                 break;
  1137. +             tp->t_state |= TS_WOPEN;
  1138. +             sleep((caddr_t)&tp->t_rawq, TTIPRI);
  1139. +         } while ((tp->t_state&TS_CARR_ON) == 0 ||
  1140. +             (dh_inout[dm]&(1<<unit)));
  1141. +     }
  1142. +     splx(s);
  1143. + }
  1144. + dmassert(addr, dm, unit, tp)
  1145. +     register struct dmdevice *addr;
  1146. +     int dm, unit;
  1147. +     struct tty *tp;
  1148. + {
  1149.       addr->dmcsr &= ~DM_SE;
  1150.       while (addr->dmcsr & DM_BUSY)
  1151. ***************
  1152. *** 696,705 ****
  1153.       addr->dmcsr = unit;
  1154.       addr->dmlstat = DML_ON;
  1155. !     if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit)))
  1156.           tp->t_state |= TS_CARR_ON;
  1157.       addr->dmcsr = DM_IE|DM_SE;
  1158. -     while ((tp->t_state&TS_CARR_ON)==0)
  1159. -         sleep((caddr_t)&tp->t_rawq, TTIPRI);
  1160. -     splx(s);
  1161.   }
  1162.   
  1163. --- 756,762 ----
  1164.       addr->dmcsr = unit;
  1165.       addr->dmlstat = DML_ON;
  1166. !     if (addr->dmlstat & DML_CAR || dhsoftCAR[dm] & (1 << unit))
  1167.           tp->t_state |= TS_CARR_ON;
  1168.       addr->dmcsr = DM_IE|DM_SE;
  1169.   }
  1170.   
  1171. //go.sysin dd *
  1172. if [ `wc -c < diff.vaxuba.dh.c` != 5035 ]; then
  1173.     made=FALSE
  1174.     echo 'error transmitting "diff.vaxuba.dh.c" --'
  1175.     echo 'length should be 5035, not' `wc -c < diff.vaxuba.dh.c`
  1176. else
  1177.     made=TRUE
  1178. fi
  1179. if [ $made = TRUE ]; then
  1180.     chmod 644 diff.vaxuba.dh.c
  1181.     echo -n '    '; ls -ld diff.vaxuba.dh.c
  1182. fi
  1183. echo 'Extracting diff.vaxuba.dz.c'
  1184. sed 's/^X//' <<'//go.sysin dd *' >diff.vaxuba.dz.c
  1185. RCS file: RCS/dz.c,v
  1186. retrieving revision 1.1.1.3
  1187. retrieving revision 1.4
  1188. diff -c2 -r1.1.1.3 -r1.4
  1189. *** /tmp/,RCSt1000449    Mon Dec  2 23:49:49 1985
  1190. --- /tmp/,RCSt2000449    Mon Dec  2 23:49:52 1985
  1191. ***************
  1192. *** 52,56 ****
  1193.   
  1194.   int    dzstart(), dzxint(), dzdma();
  1195. ! int    ttrstrt();
  1196.   struct    tty dz_tty[NDZLINE];
  1197.   int    dz_cnt = { NDZLINE };
  1198. --- 52,56 ----
  1199.   
  1200.   int    dzstart(), dzxint(), dzdma();
  1201. ! int    ttrstrt(), wakeup();
  1202.   struct    tty dz_tty[NDZLINE];
  1203.   int    dz_cnt = { NDZLINE };
  1204. ***************
  1205. *** 70,74 ****
  1206.   char    dz_brk[NDZ];
  1207.   char    dzsoftCAR[NDZ];
  1208. ! char    dz_lnen[NDZ];    /* saved line enable bits for DZ32 */
  1209.   
  1210.   /*
  1211. --- 70,76 ----
  1212.   char    dz_brk[NDZ];
  1213.   char    dzsoftCAR[NDZ];
  1214. ! char    dz_inout[NDZ];        /* outgoing mode flags */
  1215. ! char    dz_flags[NDZ];        /* permanent copy of flags */
  1216. ! char    dz_lnen[NDZ];        /* saved line enable bits for DZ32 */
  1217.   
  1218.   /*
  1219. ***************
  1220. *** 130,134 ****
  1221.           pdp++, tp++;
  1222.       }
  1223. !     dzsoftCAR[ui->ui_unit] = ui->ui_flags;
  1224.       if (dz_timer == 0) {
  1225.           dz_timer++;
  1226. --- 132,136 ----
  1227.           pdp++, tp++;
  1228.       }
  1229. !     dzsoftCAR[ui->ui_unit] = dz_flags[ui->ui_unit] = ui->ui_flags;
  1230.       if (dz_timer == 0) {
  1231.           dz_timer++;
  1232. ***************
  1233. *** 138,142 ****
  1234.   }
  1235.   
  1236. - /*ARGSUSED*/
  1237.   dzopen(dev, flag)
  1238.       dev_t dev;
  1239. --- 140,143 ----
  1240. ***************
  1241. *** 144,147 ****
  1242. --- 145,149 ----
  1243.       register struct tty *tp;
  1244.       register int unit;
  1245. +     register int dz, bit;
  1246.    
  1247.       unit = minor(dev);
  1248. ***************
  1249. *** 157,165 ****
  1250.           /* tp->t_state |= TS_HUPCLS; */
  1251.           dzparam(unit);
  1252. !     } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
  1253.           return (EBUSY);
  1254.       (void) dzmctl(dev, DZ_ON, DMSET);
  1255.       (void) spl5();
  1256. !     while ((tp->t_state & TS_CARR_ON) == 0) {
  1257.           tp->t_state |= TS_WOPEN;
  1258.           sleep((caddr_t)&tp->t_rawq, TTIPRI);
  1259. --- 159,175 ----
  1260.           /* tp->t_state |= TS_HUPCLS; */
  1261.           dzparam(unit);
  1262. !     } else if ((tp->t_state&TS_XCLUDE || flag < 0) && u.u_uid != 0)
  1263.           return (EBUSY);
  1264.       (void) dzmctl(dev, DZ_ON, DMSET);
  1265.       (void) spl5();
  1266. !     dz = unit >> 3;
  1267. !     bit = 1 << (unit & 7);
  1268. !     if (flag < 0) {
  1269. !         dz_inout[dz] |= bit;
  1270. !         dzsoftCAR[dz] |= bit;
  1271. !     }
  1272. !     while ((tp->t_state & TS_CARR_ON) == 0 ||
  1273. !         dz_inout[dz] & bit && flag >= 0) {
  1274. !         (void) dzmctl(dev, DZ_ON, DMSET);
  1275.           tp->t_state |= TS_WOPEN;
  1276.           sleep((caddr_t)&tp->t_rawq, TTIPRI);
  1277. ***************
  1278. *** 168,173 ****
  1279.       return ((*linesw[tp->t_line].l_open)(dev, tp));
  1280.   }
  1281. !  
  1282.   /*ARGSUSED*/
  1283.   dzclose(dev, flag)
  1284.       dev_t dev;
  1285. --- 178,190 ----
  1286.       return ((*linesw[tp->t_line].l_open)(dev, tp));
  1287.   }
  1288.   /*ARGSUSED*/
  1289. + dzoopen(dev, flag)
  1290. +     dev_t dev;
  1291. + {
  1292. +     return (dzopen(dev, -1));
  1293. + }
  1294.   dzclose(dev, flag)
  1295.       dev_t dev;
  1296. ***************
  1297. *** 187,195 ****
  1298.       else
  1299.           dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07)));
  1300. !     if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN) == 0)
  1301.           (void) dzmctl(dev, DZ_OFF, DMSET);
  1302.       ttyclose(tp);
  1303.   }
  1304.    
  1305.   dzread(dev, uio)
  1306.       dev_t dev;
  1307. --- 204,233 ----
  1308.       else
  1309.           dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07)));
  1310. !     if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0 || flag < 0) {
  1311.           (void) dzmctl(dev, DZ_OFF, DMSET);
  1312. +         timeout(wakeup, (caddr_t)&tp->t_state, hz);
  1313. +         sleep((caddr_t)&tp->t_state, TTOPRI);
  1314. +     }
  1315.       ttyclose(tp);
  1316. +     if (flag < 0) {
  1317. +         register int bit = 1 << (unit & 7);
  1318. +         dz_inout[dz] &= ~bit;
  1319. +         if (dz_flags[dz] & bit)
  1320. +             dzsoftCAR[dz] |= bit;
  1321. +         else
  1322. +             dzsoftCAR[dz] &= ~bit;
  1323. +         wakeup((caddr_t)&tp->t_rawq);
  1324. +     }
  1325.   }
  1326.    
  1327. + /*ARGSUSED*/
  1328. + dzoclose(dev, flag)
  1329. +     dev_t dev;
  1330. + {
  1331. +     dzclose(dev, -1);
  1332. + }
  1333.   dzread(dev, uio)
  1334.       dev_t dev;
  1335. ***************
  1336. *** 575,581 ****
  1337.       register struct tty *tp;
  1338.       register car;
  1339. !     int olddzsilos = dzsilos;
  1340.       int dztimer();
  1341. !  
  1342.       for (i = 0; i < dz_cnt ; i++) {
  1343.           dzaddr = dzpdma[i].p_addr;
  1344. --- 613,619 ----
  1345.       register struct tty *tp;
  1346.       register car;
  1347. !     int olddzsilos = dzsilos, realcar;
  1348.       int dztimer();
  1349.       for (i = 0; i < dz_cnt ; i++) {
  1350.           dzaddr = dzpdma[i].p_addr;
  1351. ***************
  1352. *** 584,598 ****
  1353.           tp = &dz_tty[i];
  1354.           bit = 1<<(i&07);
  1355. !         car = 0;
  1356. !         if (dzsoftCAR[i>>3]&bit)
  1357. !             car = 1;
  1358. !         else if (dzaddr->dzcsr & DZ_32) {
  1359.               dzaddr->dzlcs = i&07;
  1360.               dzwait(dzaddr);
  1361. !             car = dzaddr->dzlcs & DZ_CD;
  1362.           } else
  1363. !             car = dzaddr->dzmsr&bit;
  1364.           if (car) {
  1365.               /* carrier present */
  1366.               if ((tp->t_state & TS_CARR_ON) == 0) {
  1367.                   wakeup((caddr_t)&tp->t_rawq);
  1368. --- 622,638 ----
  1369.           tp = &dz_tty[i];
  1370.           bit = 1<<(i&07);
  1371. !         if (dzaddr->dzcsr & DZ_32) {
  1372.               dzaddr->dzlcs = i&07;
  1373.               dzwait(dzaddr);
  1374. !             realcar = dzaddr->dzlcs & DZ_CD;
  1375.           } else
  1376. !             realcar = dzaddr->dzmsr&bit;
  1377. !         car = 0;
  1378. !         if (realcar || dzsoftCAR[i>>3] & bit)
  1379. !             car++;
  1380.           if (car) {
  1381.               /* carrier present */
  1382. +             if (realcar && dz_inout[i>>3] & bit)
  1383. +                 dzsoftCAR[i >> 3] &= ~bit;
  1384.               if ((tp->t_state & TS_CARR_ON) == 0) {
  1385.                   wakeup((caddr_t)&tp->t_rawq);
  1386. ***************
  1387. *** 599,604 ****
  1388.                   tp->t_state |= TS_CARR_ON;
  1389.               }
  1390.           } else {
  1391. !             if ((tp->t_state&TS_CARR_ON) &&
  1392.                   (tp->t_flags&NOHANG) == 0) {
  1393.                   /* carrier lost */
  1394. --- 639,651 ----
  1395.                   tp->t_state |= TS_CARR_ON;
  1396.               }
  1397. +             else if (tp->t_state&TS_TTSTOP && tp->t_flags&MDMBUF) {
  1398. +                 tp->t_state &= ~TS_TTSTOP;
  1399. +                 ttstart(tp);
  1400. +             }
  1401.           } else {
  1402. !             if (tp->t_flags&MDMBUF) {
  1403. !                 tp->t_state |= TS_TTSTOP;
  1404. !                 dzstop(tp, 0);
  1405. !             } else if ((tp->t_state&TS_CARR_ON) &&
  1406.                   (tp->t_flags&NOHANG) == 0) {
  1407.                   /* carrier lost */
  1408. //go.sysin dd *
  1409. if [ `wc -c < diff.vaxuba.dz.c` != 5358 ]; then
  1410.     made=FALSE
  1411.     echo 'error transmitting "diff.vaxuba.dz.c" --'
  1412.     echo 'length should be 5358, not' `wc -c < diff.vaxuba.dz.c`
  1413. else
  1414.     made=TRUE
  1415. fi
  1416. if [ $made = TRUE ]; then
  1417.     chmod 644 diff.vaxuba.dz.c
  1418.     echo -n '    '; ls -ld diff.vaxuba.dz.c
  1419. fi
  1420.  
  1421.