xref: /csrg-svn/sys/vax/if/ACC/driver/if_x29.c (revision 49758)
149757Smarc /*
249757Smarc  *
349757Smarc  *     X.29 option for dda driver for UNIX and Ultrix
449757Smarc  *      ________________________________________________________
549757Smarc  *     /                                                        \
649757Smarc  *    |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
749757Smarc  *    |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
849757Smarc  *    |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
949757Smarc  *    |       AAAA AAAA      CCCC              CCCC              |
1049757Smarc  *    |      AAAA   AAAA     CCCC              CCCC              |
1149757Smarc  *    |     AAAA     AAAA    CCCC              CCCC              |
1249757Smarc  *    |    AAAA       AAAA   CCCC              CCCC              |
1349757Smarc  *    |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
1449757Smarc  *    |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
1549757Smarc  *    | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
1649757Smarc  *     \________________________________________________________/
1749757Smarc  *
1849757Smarc  *      Copyright (c) 1987 by Advanced Computer Communications
1949757Smarc  *      720 Santa Barbara Street, Santa Barbara, California  93101
2049757Smarc  *      (805) 963-9431
2149757Smarc  *
2249757Smarc  * File:
2349757Smarc  *      if_x29.c
2449757Smarc  *
2549757Smarc  * Author:
2649757Smarc  *
2749757Smarc  * Project:
2849757Smarc  *      Development of PAD on 6250 software.
2949757Smarc  *
3049757Smarc  * Function:
3149757Smarc  *      To enable network connections on ACP_XX to communicate with UNIX.
3249757Smarc  *
3349757Smarc  * Components:
3449757Smarc  *      - files if_x29.c
3549757Smarc  *
3649757Smarc  * Configuration Entry:
3749757Smarc  *
3849757Smarc  *      device dda0 at uba? csr 0166740 vector ddainta ddaintb
3949757Smarc  *
4049757Smarc  * Usage Notes:
4149757Smarc  *
4249757Smarc  *      - make devices in /dev and edit /etc/ttys for those x29
4349757Smarc  *        devices which you want in your configuration
4449757Smarc  *
4549757Smarc  * System Notes:
4649757Smarc  *
4749757Smarc  *       Refer to the installation instructions, readme.txt, which
4849757Smarc  *       are included on the driver distribution medium.
4949757Smarc  *
5049757Smarc  * Revision History at end of file
5149757Smarc  */
5249757Smarc 
5349757Smarc /*
5449757Smarc  *	For efficiency, it is a good idea to modify XXBOARDS when using
5549757Smarc  *	less than 4 boards with the X29 option.  If using more than 32
5649757Smarc  *	lines per board, you should modify XXBOARDS, XXLPERBRD, LOG2_XXBOARDS
5749757Smarc  *	and LOG2_XXLPERBRD.
5849757Smarc  *
5949757Smarc  *	Minor numbers are laid out as follows (by default):
6049757Smarc  *		(MSB) PBBLLLLL (LSB)
6149757Smarc  *	Where P is a flag to determine if the line is outbound (pad) or
6249757Smarc  *	inbound (tty).  BB is the board number (0-3), and LLLLL is the
6349757Smarc  *	X29 line on a board (0-31).  Some customers may need more than
6449757Smarc  *	32 lines/board.  If there are less than 2 boards,  one may shift
6549757Smarc  *	the break-point between lines and boards:
6649757Smarc  *
6749757Smarc  *	up to 4 boards, 32 lines/board	(default)
6849757Smarc  *		(MSB) PBBLLLLL (LSB)
6949757Smarc  *			XXBOARDS  = 4,   LOG2_XXBOARDS  = 2
7049757Smarc  *			XXLPERBRD = 32,	 LOG2_XXLPERBRD = 5
7149757Smarc  *	up to 2 boards, 64 lines/board:
7249757Smarc  *		(MSB) PBLLLLLL (LSB)
7349757Smarc  *			XXBOARDS  = 2,   LOG2_XXBOARDS  = 1
7449757Smarc  *			XXLPERBRD = 64,  LOG2_XXLPERBRD = 6
7549757Smarc  *	only 1 board, 128 (actually, 126, as 126 = max svc):
7649757Smarc  *		(MSB) PLLLLLLL (LSB)
7749757Smarc  *			XXBOARDS  = 1,   LOG2_XXBOARDS  = 0
7849757Smarc  *			XXLPERBRD = 128, LOG2_XXLPERBRD = 7
7949757Smarc  *
8049757Smarc  *	(obviously, these are all powers of two)
8149757Smarc  */
8249757Smarc 
8349757Smarc #define	XXBOARDS	4	/* # boards running x29 */
8449757Smarc #define	LOG2_XXBOARDS	2	/* # bits of board info */
8549757Smarc 
8649757Smarc #define XXLPERBRD	32	/* # lines per board */
8749757Smarc #define	LOG2_XXLPERBRD	5	/* # bits of line info */
8849757Smarc 
8949757Smarc /*
9049757Smarc  * If you require an 8-bit data path and have no parity misconfigurations,
9149757Smarc  * you may change PARITY_MASKs to 0377.  This will leave parity stripping
9249757Smarc  * to the ttdriver.  However,  the ttdriver won't strip parity when in
9349757Smarc  * raw mode (e.g. at the Password: prompt),  so one symptom of a parity
9449757Smarc  * misconfiguration is that users can't login (CR gets received as 0x8D).
9549757Smarc  */
9649757Smarc 
9749757Smarc #define	INPUT_PARITY_MASK  0177	/* strip off the 8th bit */
9849757Smarc #define	OUTPUT_PARITY_MASK 0377	/* don't strip off the 8th bit */
9949757Smarc 
10049757Smarc /*
10149757Smarc  * macro to translate a device number to the unit (i.e. ACP_n250)
10249757Smarc  * with which it is associated and the port on said unit
10349757Smarc  */
10449757Smarc 
10549757Smarc #define UNIT(x) ((minor(x) >> LOG2_XXLPERBRD) & LOG2_XXBOARDS)
10649757Smarc 
10749757Smarc #define LINE(x)	  (minor(x) & 0177)	/* index into line table */
10849757Smarc #define XXSHOW(x) (minor(x) == 255)	/* special "show" device */
10949757Smarc #define IS_PAD(x) (minor(x) & 0200)	/* msb is the pad/tty selector */
11049757Smarc #define MAJLINE(x) ((x) & ~0x80)	/* major plus corrected minor # */
11149757Smarc 
11249757Smarc #define NXXLINES        (XXBOARDS * XXLPERBRD)	/* number of total x29 lines */
11349757Smarc 
11449757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
11549757Smarc /*%%                                                             %%*/
11649757Smarc /*%%                   LOCAL  FUNCTIONS                          %%*/
11749757Smarc /*%%                                                             %%*/
11849757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
11949757Smarc 
12049757Smarc PRIVATE void    xxcntl();
12149757Smarc PRIVATE void    xxclear();
12249757Smarc PRIVATE void    xxshow();
12349757Smarc PRIVATE void    xxpadhandle();
12449757Smarc PRIVATE int     xxpadparse();
12549757Smarc PRIVATE int     xxpadcall();
12649757Smarc PRIVATE void    xxpadmsg();
12749757Smarc PRIVATE void	xx_qbit_msg();
12849757Smarc PRIVATE void    xx_tp_hangup();
12949757Smarc PRIVATE void    x29_init();
13049757Smarc PRIVATE void    x29_dhandle();
13149757Smarc PRIVATE int	x29_break_reply_is_required();
13249757Smarc 
13349757Smarc #if ACC_ULTRIX >= 30
13449757Smarc static  int	ttbreakc();		/* always keep this private */
13549757Smarc #endif
13649757Smarc 
13749757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
13849757Smarc /*%%                                                             %%*/
13949757Smarc /*%%                   LOCAL  VARIABLES                          %%*/
14049757Smarc /*%%                                                             %%*/
14149757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
14249757Smarc 
14349757Smarc #define SET_PAD		2
14449757Smarc #define READ_PAD	4
14549757Smarc #define SET_READ_PAD	6
14649757Smarc #define PAR_INDICATION	0
14749757Smarc #define INVITE_CLEAR	1
14849757Smarc #define BREAK_INDIC	3
14949757Smarc #define PAD_ERROR	5
15049757Smarc 
15149757Smarc /* command codes */
15249757Smarc #define XX_C_BREAK	001
15349757Smarc #define XX_C_PAD	002
15449757Smarc #define XX_C_CLOSE	003
15549757Smarc #define XX_C_HOST	004
15649757Smarc 
15749757Smarc struct tty      xx_tty[NXXLINES];	/* tty structures */
15849757Smarc 
15949757Smarc #define MODE_UNUSED 0			/* !just for sanity checks only! */
16049757Smarc #define	MODE_HOST 1			/* port in host mode (incoming) */
16149757Smarc #define	MODE_PAD  2			/* port in pad mode (outgoing) */
16249757Smarc 
16349757Smarc char            xxmode[NXXLINES];	/* mode of port */
16449757Smarc 
16549757Smarc int             xxstart();
16649757Smarc 
16749757Smarc typedef struct {
16849757Smarc     char            ref;
16949757Smarc     char            val;
17049757Smarc } x29_pad_pair;
17149757Smarc 
17249757Smarc PRIVATE x29_pad_pair x29_break_ack_params[] =
17349757Smarc {
17449757Smarc  8, 0				/* ref 8 -- normal output to terminal */
17549757Smarc };
17649757Smarc 
17749757Smarc PRIVATE x29_pad_pair x29_callout_params[] =
17849757Smarc {
17949757Smarc  1, 0				/* ref 1 -- no recall char */
18049757Smarc };
18149757Smarc 
18249757Smarc PRIVATE x29_pad_pair x29_callin_setparams[] =
18349757Smarc { /* these are the preferred paramters when calling in to Unix */
18449757Smarc  2, 0,				/* ref 2 -- no echo */
18549757Smarc  3, 127,			/* ref 3 -- forward data on any char */
18649757Smarc  8, 0,				/* ref 8 -- normal data delivery to terminal */
18749757Smarc  9, 0,				/* ref 9 -- no padding after carriage return */
18849757Smarc  10, 0,				/* ref 10 -- no line folding */
18949757Smarc  13, 0,				/* ref 13 -- no line feed after CR */
19049757Smarc  15, 0				/* ref 15 -- no local edit */
19149757Smarc };
19249757Smarc 
19349757Smarc /******************************************************************************
19449757Smarc  *  PAD CONTROL INFORMATION AND DEFINITIONS
19549757Smarc  ******************************************************************************/
19649757Smarc 
19749757Smarc /* definitions for the pad state field p_state */
19849757Smarc #define PS_IDLE	0		/* not opened state */
19949757Smarc #define PS_COM  1		/* the pad for this line is in command state */
20049757Smarc #define PS_PAD  2		/* this line has data passing though the pad */
20149757Smarc #define PS_WAIT	3		/* waiting state */
20249757Smarc #define PS_XFR	4		/* data transfer state */
20349757Smarc 
20449757Smarc #define P_LINELEN	20
20549757Smarc #define P_NOBLOCK	0
20649757Smarc 
20749757Smarc typedef struct padinfo {
20849757Smarc     short           p_state;	/* pad state */
20949757Smarc     char            p_line[P_LINELEN];	/* built up line */
21049757Smarc     char            p_idx;	/* index into p_line */
21149757Smarc     int		    p_flow;	/* index into mbuf when flow off,
21249757Smarc 				   P_NOBLOCK if not flowed off */
21349757Smarc     struct mbuf    *p_msav;	/* place to hang mbuf when flow controlled */
21449757Smarc     struct mbuf    *p_mchsav;	/* place to save mbuf chain '' '' '' */
21549757Smarc } padinfo;
21649757Smarc padinfo         xx_padinfo[NXXLINES];
21749757Smarc 
21849757Smarc 
21949757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
22049757Smarc /*%%                                                             %%*/
22149757Smarc /*%%                   GLOBAL ROUTINES                           %%*/
22249757Smarc /*%%                                                             %%*/
22349757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
22449757Smarc 
22549757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
22649757Smarc /*%%                       XXOPEN()                              %%*/
22749757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
22849757Smarc /*                                                                 */
22949757Smarc /*  Purpose:                                                       */
23049757Smarc /*                                                                 */
23149757Smarc /*  Open a line.                                                   */
23249757Smarc /*                                                                 */
23349757Smarc /*  Call:           xxopen(dev, flag)                              */
23449757Smarc /*  Argument:       dev:   device                                  */
23549757Smarc /*                  flag:  indicates type of open, "nonblocking"   */
23649757Smarc /*                         "or block if in use"                    */
23749757Smarc /*  Returns:        0 for success, else nonzero error code         */
23849757Smarc /*  Called by:      kernel software software,  this routine is in  */
23949757Smarc /*                  the cdevsw table                               */
24049757Smarc /*                                                                 */
24149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
24249757Smarc 
24349757Smarc /*ARGSUSED*/
xxopen(dev,flag)24449757Smarc xxopen(dev, flag)
24549757Smarc dev_t           dev;
24649757Smarc int             flag;
24749757Smarc {
24849757Smarc     register struct tty *tp;
24949757Smarc     register        d;
25049757Smarc     register        s;
25149757Smarc     int             unit,
25249757Smarc                     i;
25349757Smarc #if ACC_ULTRIX > 00
25449757Smarc     int             inuse;	/* store inuse bit while sleeping */
25549757Smarc #endif
25649757Smarc 
25749757Smarc     unit = UNIT(dev);
25849757Smarc     d = LINE(dev);
25949757Smarc 
26049757Smarc     if (XXSHOW(dev)) {		/* minor device 255 */
26149757Smarc 	xxshow();
26249757Smarc 	return (EPIPE);
26349757Smarc     }
26449757Smarc 
26549757Smarc     /* PST NOTE TO SELF: change the test as follows:
26649757Smarc      *	make this d >= NXXLINES, then check to see if unit is present,
26749757Smarc      *  Keep that sleep() in the thingy below, so we don't get bouncing
26849757Smarc      *  gettys eating up cpu time.
26949757Smarc      */
27049757Smarc     if ((d >= NXXLINES))
27149757Smarc 	return (ENXIO);
27249757Smarc 
27349757Smarc     /* wait for interface to come up */
27449757Smarc     while (dda_softc[unit].dda_state != S_LINK_UP)
27549757Smarc 	sleep(&dda_softc[unit].dda_state, TTIPRI);
27649757Smarc 
27749757Smarc     tp = &xx_tty[d];
27849757Smarc     if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0)
27949757Smarc 	return EBUSY;
28049757Smarc 
28149757Smarc     /* make sure the port isn't already open in a conflicting manner */
28249757Smarc     /* i.e. can't open /dev/padJ0 and /dev/ttyJ0 at the same time */
28349757Smarc     if (tp->t_state & (TS_WOPEN | TS_ISOPEN)) {
28449757Smarc 	if ((IS_PAD(dev) && (xxmode[d] == MODE_HOST)) ||
28549757Smarc 	    ((!IS_PAD(dev)) && (xxmode[d] == MODE_PAD)))
28649757Smarc 	    return EBUSY;
28749757Smarc     }
28849757Smarc 
28949757Smarc #ifdef	DDADEBUG
29049757Smarc 	if (DDADBCH(96, unit)) {
29149757Smarc 		DDALOG(LOG_DEBUG)
29249757Smarc 		    "dda%d:(x29) open line %d flag %o in %s mode\n",
29349757Smarc 		    unit, d, flag, (IS_PAD(dev) ? "pad" : "host")
29449757Smarc 		DDAELOG;
29549757Smarc 	}
29649757Smarc #endif  DDADEBUG
29749757Smarc 
29849757Smarc     tp->t_oproc = xxstart;
29949757Smarc     tp->t_state |= TS_WOPEN;
30049757Smarc 
30149757Smarc     /* if first open initialize state */
30249757Smarc     if ((tp->t_state & TS_ISOPEN) == 0) {
30349757Smarc 	ttychars(tp);
30449757Smarc 
30549757Smarc #if ACC_ULTRIX >= 30		/* posix compliant tty driver */
30649757Smarc 	if (tp->t_cflag & CBAUD == 0) {
30749757Smarc 	    tp->t_iflag = IGNPAR | ICRNL | IXON | IXANY | IXOFF;
30849757Smarc 	    tp->t_oflag = OPOST | ONLCR;
30949757Smarc 	    tp->t_cflag = B9600 | CS8 | CREAD | HUPCL;
31049757Smarc 	    tp->t_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL;
31149757Smarc 	    tp->t_line = 0;
31249757Smarc 	}
31349757Smarc #else				/* v7 tty driver */
31449757Smarc 	if (tp->t_ispeed == 0) {
31549757Smarc 	    tp->t_ispeed = B9600;
31649757Smarc 	    tp->t_ospeed = B9600;
31749757Smarc 	    tp->t_flags = CRMOD | ANYP;
31849757Smarc 	}
31949757Smarc #endif
32049757Smarc 	xxparam(dev);
32149757Smarc     }
32249757Smarc     if (IS_PAD(dev)) {
32349757Smarc 	tp->t_state |= TS_CARR_ON;
32449757Smarc 	xxmode[d] = MODE_PAD;
32549757Smarc 	xxcntl(tp, XX_C_PAD, unit);
32649757Smarc     } else {
32749757Smarc 	if ((tp->t_state & TS_CARR_ON) == 0) {
32849757Smarc 	    xxmode[d] = MODE_HOST;
32949757Smarc 	    xxcntl(tp, XX_C_HOST, unit);
33049757Smarc 	    tp->t_flags |= ECHO;
33149757Smarc #if ACC_ULTRIX < 31	/* on everything other than Ultrix 3.1 */
33249757Smarc 	    /* on close tell ACP_XX to drop line */
33349757Smarc 	    tp->t_state |= TS_HUPCLS;
33449757Smarc #endif
33549757Smarc 	}
33649757Smarc     }
33749757Smarc     /* if xxcntl did not get called (state had carrier off) or xxcntl's
33849757Smarc      * search for a free lcn failed, then t_addr will be 0, so punt */
33949757Smarc     if (tp->t_addr == 0) {
34049757Smarc 	tp->t_pgrp = 0;
34149757Smarc 	tp->t_state = 0;
34249757Smarc 	xxmode[d] = MODE_UNUSED;
34349757Smarc 	return (EBUSY);
34449757Smarc     }
34549757Smarc     xx_padinfo[d].p_flow = P_NOBLOCK;
34649757Smarc     s = splimp();
34749757Smarc 
34849757Smarc #if ACC_ULTRIX > 00
34949757Smarc     if (flag & O_NDELAY) {
35049757Smarc 	if (!IS_PAD(dev))
35149757Smarc 	    tp->t_state |= TS_ONDELAY;
35249757Smarc     } else
35349757Smarc #endif
35449757Smarc 	while ((tp->t_state & TS_CARR_ON) == 0) {
35549757Smarc 	    tp->t_state |= TS_WOPEN;
35649757Smarc #if ACC_ULTRIX > 00
35749757Smarc 	    inuse = tp->t_state & TS_INUSE;
35849757Smarc #endif
35949757Smarc 	    sleep(&tp->t_rawq, TTIPRI);
36049757Smarc 
36149757Smarc 	    /* wakeup came from xxclear */
36249757Smarc 	    if ((tp->t_state & TS_WOPEN) == 0) {
36349757Smarc 		splx(s);
36449757Smarc 		return (EPIPE);
36549757Smarc 	    }
36649757Smarc #if ACC_ULTRIX > 00
36749757Smarc 	    /* if port became "inuse" while we slept, return */
36849757Smarc 	    if ((flag & O_BLKINUSE) && (!inuse) &&
36949757Smarc 		(tp->t_state & TS_INUSE)) {
37049757Smarc 		splx(s);
37149757Smarc 		return (EALREADY);
37249757Smarc 	    }
37349757Smarc #endif
37449757Smarc 	}
37549757Smarc 
37649757Smarc     splx(s);
37749757Smarc     i = ((*linesw[tp->t_line].l_open) (dev, tp));
37849757Smarc     if (tp->t_pgrp == 0)
37949757Smarc 	tp->t_pgrp = u.u_procp->p_pid;
38049757Smarc     return (i);
38149757Smarc }
38249757Smarc 
38349757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38449757Smarc /*%%                       XXCLOSE()                             %%*/
38549757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38649757Smarc /*                                                                 */
38749757Smarc /*  Purpose:                                                       */
38849757Smarc /*                                                                 */
38949757Smarc /*  Close a line.                                                  */
39049757Smarc /*                                                                 */
39149757Smarc /*  Call:           xxclose(dev, flag)                             */
39249757Smarc /*  Argument:       dev:   device                                  */
39349757Smarc /*                  flag:  unused                                  */
39449757Smarc /*  Returns:        nothing                                        */
39549757Smarc /*  Called by:      kernel software,  this routine is in the	   */
39649757Smarc /*		    cdevsw table                                   */
39749757Smarc /*                                                                 */
39849757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39949757Smarc 
40049757Smarc /*ARGSUSED*/
xxclose(dev,flag,mode,p)401*49758Smarc xxclose(dev, flag, mode, p)
40249757Smarc dev_t           dev;
403*49758Smarc int             flag, mode;
404*49758Smarc struct proc	*p;
40549757Smarc {
40649757Smarc     register struct tty *tp;
40749757Smarc     register        d;
40849757Smarc     d = LINE(dev);
40949757Smarc     tp = &xx_tty[d];
41049757Smarc 
41149757Smarc #ifdef	DDADEBUG
41249757Smarc 	if (DDADBCH(97, UNIT(dev))) {
41349757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) closing line %d\n", UNIT(dev), d
41449757Smarc 		DDAELOG;
41549757Smarc 	}
41649757Smarc #endif  DDADEBUG
41749757Smarc 
41849757Smarc 	/* PST NOTE TO SELF:
41949757Smarc 	 *	Add the 629 driver code for timing out the close below,
42049757Smarc 	 *	because the line could be flowed off and it would hang
42149757Smarc 	 * 	forever */
42249757Smarc 
423*49758Smarc     (*linesw[tp->t_line].l_close) (tp, flag);
42449757Smarc 
42549757Smarc #if ACC_ULTRIX >= 31
42649757Smarc     if ((tp->t_cflag & HUPCL) || ((tp->t_state & TS_ISOPEN) == 0)) {
42749757Smarc #else
42849757Smarc     if ((tp->t_state & TS_HUPCLS) || ((tp->t_state & TS_ISOPEN) == 0)) {
42949757Smarc #endif
43049757Smarc 
43149757Smarc #ifdef	DDADEBUG
43249757Smarc 	if (DDADBCH(97, UNIT(dev))) {
43349757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) close: tp->t_state = %x\n",
43449757Smarc 				  UNIT(dev), tp->t_state
43549757Smarc 		DDAELOG;
43649757Smarc 	}
43749757Smarc #endif  DDADEBUG
43849757Smarc 
43949757Smarc 	if (tp->t_state & TS_CARR_ON)
44049757Smarc 	    xxcntl(tp, XX_C_CLOSE, UNIT(dev));
44149757Smarc 	tp->t_state &= ~TS_CARR_ON;
44249757Smarc 	xxmode[d] = MODE_UNUSED;
44349757Smarc     }
44449757Smarc     ttyclose(tp);
44549757Smarc }
44649757Smarc 
44749757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
44849757Smarc /*%%                       XXREAD()                              %%*/
44949757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
45049757Smarc /*                                                                 */
45149757Smarc /*  Purpose:                                                       */
45249757Smarc /*                                                                 */
45349757Smarc /*  Read from a line.                                              */
45449757Smarc /*                                                                 */
45549757Smarc /*  Call:           xxread(dev, uio)                               */
45649757Smarc /*  Argument:       dev:   device                                  */
45749757Smarc /*                  uio:   pointer to uio structure                */
45849757Smarc /*  Returns:        0 for success, else nonzero error code         */
45949757Smarc /*  Called by:      kernel software,  this routine is in	   */
46049757Smarc /*                  the cdevsw table                               */
46149757Smarc /*                                                                 */
46249757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
46349757Smarc 
xxread(dev,uio)46449757Smarc xxread(dev, uio)
46549757Smarc dev_t           dev;
46649757Smarc struct uio     *uio;
46749757Smarc {
46849757Smarc     register struct tty *tp;
46949757Smarc     register int    l,
47049757Smarc                     error;
47149757Smarc 
47249757Smarc     if (dda_softc[UNIT(dev)].dda_state != S_LINK_UP)
47349757Smarc 	return (ENXIO);
47449757Smarc 
47549757Smarc     l = LINE(dev);
47649757Smarc     tp = &xx_tty[l];
47749757Smarc     error = (*linesw[tp->t_line].l_read)(tp, uio);
47849757Smarc 
47949757Smarc     if (xx_padinfo[l].p_flow != P_NOBLOCK) {	/* currently blocked? */
48049757Smarc 	if (tp->t_flags & (RAW | CBREAK)) {	/* using raw q? */
48149757Smarc 	    if (tp->t_rawq.c_cc < TTYHOG / 8) {	/* if rawq is low, then
48249757Smarc 						 * it's time to unblock */
48349757Smarc 		x29_dhandle(&dda_softc[UNIT(dev)],
48449757Smarc 			    (struct dda_cb *) (tp->t_addr), 1);
48549757Smarc 	    }
48649757Smarc 	/* else cooked mode, different test */
48749757Smarc 	/* canonical q empty? then it's time to unblock */
48849757Smarc 	} else if (tp->t_canq.c_cc == 0) {
48949757Smarc 	    x29_dhandle(&dda_softc[UNIT(dev)],
49049757Smarc 			(struct dda_cb *) (tp->t_addr), 1);
49149757Smarc 	}
49249757Smarc     }
49349757Smarc     return (error);
49449757Smarc }
49549757Smarc 
49649757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
49749757Smarc /*%%                       XXWRITE()                             %%*/
49849757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
49949757Smarc /*                                                                 */
50049757Smarc /*  Purpose:                                                       */
50149757Smarc /*                                                                 */
50249757Smarc /*  Write on a line.                                               */
50349757Smarc /*                                                                 */
50449757Smarc /*  Call:           xxwrite(dev, uio)                              */
50549757Smarc /*  Argument:       dev:   device                                  */
50649757Smarc /*                  uio:   pointer to uio structure                */
50749757Smarc /*  Returns:        0 for success, else nonzero error code         */
50849757Smarc /*  Called by:      kernel software software,  this routine is in  */
50949757Smarc /*                  the cdevsw table                               */
51049757Smarc /*                                                                 */
51149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51249757Smarc 
xxwrite(dev,uio)51349757Smarc xxwrite(dev, uio)
51449757Smarc dev_t           dev;
51549757Smarc struct uio     *uio;
51649757Smarc {
51749757Smarc     register struct tty *tp;
51849757Smarc     if (dda_softc[UNIT(dev)].dda_state != S_LINK_UP)
51949757Smarc 	return (ENXIO);
52049757Smarc     tp = &xx_tty[LINE(dev)];
52149757Smarc     return (*linesw[tp->t_line].l_write)(tp, uio);
52249757Smarc }
52349757Smarc 
52449757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
52549757Smarc /*%%                       XXIOCTL()                             %%*/
52649757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
52749757Smarc /*                                                                 */
52849757Smarc /*  Purpose:                                                       */
52949757Smarc /*                                                                 */
53049757Smarc /*  Process ioctl request.                                         */
53149757Smarc /*                                                                 */
53249757Smarc /*  Call:           xxioctl(dev, cmd, data, flag)                  */
53349757Smarc /*  Argument:       dev:   device                                  */
53449757Smarc /*                  cmd:   ioctl command                           */
53549757Smarc /*                  data:  pointer to data                         */
53649757Smarc /*                  flag:  ignored                                 */
53749757Smarc /*  Returns:        0 for sucess, else nonzero error code          */
53849757Smarc /*  Called by:      kernel software software,  this routine is in  */
53949757Smarc /*                  the cdevsw table                               */
54049757Smarc /*                                                                 */
54149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54249757Smarc 
54349757Smarc #define TIOACCQBIT (int)(0x80800000|('t'<<8)|125)
54449757Smarc 
xxioctl(dev,cmd,data,flag)54549757Smarc xxioctl(dev, cmd, data, flag)
54649757Smarc dev_t           dev;
54749757Smarc caddr_t         data;
54849757Smarc {
54949757Smarc     register struct tty *tp;
55049757Smarc     int             error;
55149757Smarc     tp = &xx_tty[LINE(dev)];
55249757Smarc     if (cmd == TIOACCQBIT) {
55349757Smarc #ifdef	DDADEBUG
55449757Smarc 	if (DDADBCH(98, UNIT(dev))) {
55549757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) ioctl qbit msg: cmd=%x ACC=%x\n",
55649757Smarc 				  UNIT(dev), cmd, TIOACCQBIT
55749757Smarc 		DDAELOG;
55849757Smarc 	}
55949757Smarc #endif  DDADEBUG
56049757Smarc 	xx_qbit_msg(tp, UNIT(dev), data);
56149757Smarc 	return (0);
56249757Smarc     }
56349757Smarc     error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag);
56449757Smarc     if (error >= 0)
56549757Smarc 	return (error);
56649757Smarc     error = ttioctl(tp, cmd, data, flag);
56749757Smarc     if (error >= 0) {
56849757Smarc 	if (cmd == TIOCSETP || cmd == TIOCSETN)
56949757Smarc 	    xxparam(dev);
57049757Smarc 	return (error);
57149757Smarc     }
57249757Smarc     switch (cmd) {
57349757Smarc     case TIOCREMOTE:
57449757Smarc 	if (xxmode[LINE(dev)] == 0)
57549757Smarc 	    return (EBUSY);
57649757Smarc 	xxcntl(tp, XX_C_PAD, UNIT(dev));
57749757Smarc 	break;
57849757Smarc     case TIOCSBRK:
57949757Smarc 	xxcntl(tp, XX_C_BREAK, UNIT(dev));
58049757Smarc 	break;
58149757Smarc     case TIOCCBRK:
58249757Smarc     case TIOCSDTR:
58349757Smarc     case TIOCCDTR:
58449757Smarc 	break;
58549757Smarc     default:
58649757Smarc 	return (ENOTTY);
58749757Smarc     }
58849757Smarc     return (0);
58949757Smarc }
59049757Smarc 
59149757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59249757Smarc /*%%                        XXPARAM()                            %%*/
59349757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59449757Smarc /*                                                                 */
59549757Smarc /*  Purpose:                                                       */
59649757Smarc /*                                                                 */
59749757Smarc /*  Set parameters from open or stty.                              */
59849757Smarc /*  This routine is being left in as a dummy in case in the future */
59949757Smarc /*  there is a mechanism for the host to send information i.e.     */
60049757Smarc /*  "hangup line" to the ACP _XX                                   */
60149757Smarc /*                                                                 */
60249757Smarc /*  Call:           xxparam(dev)                                   */
60349757Smarc /*  Argument:       dev:   device                                  */
60449757Smarc /*  Returns:        none                                           */
60549757Smarc /*  Called by:      none                                           */
60649757Smarc /*                                                                 */
60749757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60849757Smarc /*ARGSUSED*/
xxparam(dev)60949757Smarc xxparam(dev)
61049757Smarc dev_t           dev;
61149757Smarc {
61249757Smarc }
61349757Smarc 
61449757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
61549757Smarc /*%%                        XXSTART()                            %%*/
61649757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
61749757Smarc /*                                                                 */
61849757Smarc /*  Purpose:                                                       */
61949757Smarc /*                                                                 */
62049757Smarc /*  Start (restart) transmission on a given line.  This is the     */
62149757Smarc /*  start routine which is called from above by the tty driver and */
62249757Smarc /*  from below on a transmission complete interrupt for a given    */
62349757Smarc /*  line.                                                          */
62449757Smarc /*                                                                 */
62549757Smarc /*  Call:           xxstart(tp)                                    */
62649757Smarc /*  Argument:       tp:   pointer to tty structure                 */
62749757Smarc /*  Returns:        none                                           */
62849757Smarc /*  Called by:      tty driver                                     */
62949757Smarc /*                  xxreset()                                      */
63049757Smarc /*                                                                 */
63149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
63249757Smarc 
xxstart(tp)63349757Smarc xxstart(tp)
63449757Smarc register struct tty *tp;
63549757Smarc {
63649757Smarc     register struct dda_softc *ds;
63749757Smarc     register int    nch,
63849757Smarc                     cc,
63949757Smarc 		    k;
64049757Smarc     register struct dda_cb *dc;
64149757Smarc     register char  *cp,
64249757Smarc                    *p;
64349757Smarc     struct ifqueue *oq;
64449757Smarc     struct mbuf    *m;
64549757Smarc     padinfo	   *pp;
64649757Smarc     int             unit,
64749757Smarc                     line,
64849757Smarc                     s,
64949757Smarc 		    j;
65049757Smarc     extern int      ttrstrt();
65149757Smarc 
65249757Smarc     line = tp - xx_tty;
65349757Smarc     unit = UNIT(line);
65449757Smarc     dc = (struct dda_cb *) tp->t_addr;
65549757Smarc     ds = &dda_softc[unit];
65649757Smarc     pp = &xx_padinfo[line];
65749757Smarc 
65849757Smarc     s = splimp();
65949757Smarc 
66049757Smarc #ifdef	DDADEBUG
66149757Smarc     if (DDADBCH(99, unit)) {
66249757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) xxstart: line %d t_state = %x\n",
66349757Smarc 			  unit, line, tp->t_state
66449757Smarc 	DDAELOG;
66549757Smarc     }
66649757Smarc #endif  DDADEBUG
66749757Smarc 
66849757Smarc     /* If it's currently active, or delaying, no need to do anything. */
66949757Smarc     if ((tp->t_state & TS_CARR_ON) == 0) {
67049757Smarc 	tp->t_state &= ~(TS_TTSTOP | TS_BUSY);
67149757Smarc 	ttyflush(tp, FREAD | FWRITE);
67249757Smarc 	tp->t_state &= ~TS_ASLEEP;
67349757Smarc 	wakeup((caddr_t) &tp->t_outq);
67449757Smarc 	goto out;
67549757Smarc     }
67649757Smarc     if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
67749757Smarc 	goto out;
67849757Smarc 
67949757Smarc     /* wait for free */
68049757Smarc     if (dda_softc[unit].dda_state != S_LINK_UP) {
68149757Smarc 	ttyflush(tp, FREAD | FWRITE);
68249757Smarc         DMESG(unit, 96, (DDALOG(LOG_ERR)
68349757Smarc 			"dda%d:(x29) xxstart: unit offline\n", unit DDAELOG) );
68449757Smarc 	goto out;
68549757Smarc     }
68649757Smarc     /* If the writer was sleeping on output overflow, wake him when low tide
68749757Smarc      * is reached. */
68849757Smarc     if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
68949757Smarc 	if (tp->t_state & TS_ASLEEP) {
69049757Smarc 	    tp->t_state &= ~TS_ASLEEP;
69149757Smarc 	    wakeup((caddr_t) &tp->t_outq);
69249757Smarc 	}
69349757Smarc 	if (tp->t_wsel) {
69449757Smarc 	    selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
69549757Smarc 	    tp->t_wsel = 0;
69649757Smarc 	    tp->t_state &= ~TS_WCOLL;
69749757Smarc 	}
69849757Smarc     }
69949757Smarc     /* restart transmission unless output queue is empty */
70049757Smarc     if (tp->t_outq.c_cc == 0)
70149757Smarc 	goto out;
70249757Smarc 
70349757Smarc     /* if this is an outbound pad line and it's in command mode */
70449757Smarc     if (pp->p_state == PS_COM) {
70549757Smarc 	xxpadhandle(ds, tp, pp);
70649757Smarc 	goto out;
70749757Smarc     }
70849757Smarc 
70949757Smarc     /* Allocate an mbuf to stuff the chars into */
71049757Smarc     m = 0;
71149757Smarc     MGET(m, M_DONTWAIT, MT_DATA);
71249757Smarc     if (m == 0) {
71349757Smarc         DMESG(unit, 97, (DDALOG(LOG_ERR)
71449757Smarc 			"dda%d:(x29) xxstart: could not get mbuf\n",
71549757Smarc 			unit DDAELOG) );
71649757Smarc 	goto out;
71749757Smarc     }
71849757Smarc     cp = mtod(m, char *);
71949757Smarc     cc = 0;
72049757Smarc 
72149757Smarc     /* copy at most MLEN-1 chars out -- must save one byte for subfunc */
72249757Smarc     while ((cc < MLEN - 1) && (tp->t_outq.c_cc > 0)) {
72349757Smarc 	if (tp->t_flags & (RAW | LITOUT))
72449757Smarc 	    nch = ndqb(&tp->t_outq, 0);
72549757Smarc 	else {
72649757Smarc 	    nch = ndqb(&tp->t_outq, 0200);
72749757Smarc 	    if (nch == 0) {	/* if first item was a delay */
72849757Smarc 		(void) getc(&tp->t_outq);	/* discard the character */
72949757Smarc 		continue;
73049757Smarc 	    }
73149757Smarc 	}
73249757Smarc 	if (nch > (MLEN - 1) - cc)
73349757Smarc 	    nch = (MLEN - 1) - cc;
73449757Smarc 
73549757Smarc 	/* If any characters were set up, start transmission; */
73649757Smarc 	if (nch) {
73749757Smarc 	    j = q_to_b(&tp->t_outq, cp, nch);
73849757Smarc 
73949757Smarc #if OUTPUT_PARITY_MASK != 0377
74049757Smarc 	    /* strip all characters as desired */
74149757Smarc 	    for (p = cp, k = j; k; k--, p++)
74249757Smarc 		*p &= OUTPUT_PARITY_MASK;
74349757Smarc #endif
74449757Smarc 
74549757Smarc #ifdef	DDADEBUG
74649757Smarc 	    if (DDADBCH(100, unit) && j != nch) {
74749757Smarc 		DDALOG(LOG_DEBUG)
74849757Smarc 		    "dda%d:(x29) xxstart: asked for %d got %d chars\n",
74949757Smarc 		    unit, nch, j
75049757Smarc 		DDAELOG;
75149757Smarc 	    }
75249757Smarc #endif  DDADEBUG
75349757Smarc 
75449757Smarc 	    cc += nch;
75549757Smarc 	    cp += nch;
75649757Smarc 	} else
75749757Smarc 	    break;
75849757Smarc     }
75949757Smarc 
76049757Smarc #ifdef	DDADEBUG
76149757Smarc     if (DDADBCH(101, unit)) {
76249757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) xxstart: mbuf %x len %d\n",
76349757Smarc 			  unit, m, m->m_len
76449757Smarc 	DDAELOG;
76549757Smarc     }
76649757Smarc #endif
76749757Smarc 
76849757Smarc     /* if any data was stuffed into the mbuf then send it */
76949757Smarc     if (cc) {
77049757Smarc 	m->m_dat[MLEN - 1] = 0;	/* subfunction: no Q-bit */
77149757Smarc 	m->m_len = cc;
77249757Smarc 	oq = &(dc->dc_oq);	/* point to output queue */
77349757Smarc 	if (IF_QFULL(oq)) {	/* if q full */
77449757Smarc 	    IF_DROP(oq);	/* drop the data */
77549757Smarc 	    m_freem(m);
77649757Smarc 	    ds->dda_if.if_collisions++;	/* for netstat display */
77749757Smarc 	    splx(s);
77849757Smarc 	    return (ENOBUFS);
77949757Smarc 	}
78049757Smarc 	IF_ENQUEUE(oq, m);	/* otherwise queue it */
78149757Smarc 	tp->t_state |= TS_BUSY;
78249757Smarc 	dda_start(ds, dc);	/* and try to output */
78349757Smarc     } else
78449757Smarc 	m_freem(m);
78549757Smarc 
78649757Smarc out:
78749757Smarc     if (dc->dc_lcn != 0)	/* something left in oq? */
78849757Smarc 	dda_start(ds, dc);	/* restart output */
78949757Smarc     splx(s);
79049757Smarc     return (0);
79149757Smarc }
79249757Smarc 
79349757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
79449757Smarc /*%%                        XXRESET()                            %%*/
79549757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
79649757Smarc /*                                                                 */
79749757Smarc /*  Purpose:                                                       */
79849757Smarc /*                                                                 */
79949757Smarc /*  In response to UNIBUS reset, reset state and restart           */
80049757Smarc /*  transmitters.                                                  */
80149757Smarc /*                                                                 */
80249757Smarc /*  Call:           xxreset(uban)                                  */
80349757Smarc /*  Argument:       uban:  UNIBUS adaptor number                   */
80449757Smarc /*  Returns:        none                                           */
80549757Smarc /*  Called by:      kernel software in response to UNIBUS reset    */
80649757Smarc /*                                                                 */
80749757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
80849757Smarc /*ARGSUSED*/
xxreset(uban)80949757Smarc xxreset(uban)
81049757Smarc int uban;
81149757Smarc {
81249757Smarc }
81349757Smarc 
81449757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
81549757Smarc /*%%                        XXSTOP()                             %%*/
81649757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
81749757Smarc /*                                                                 */
81849757Smarc /*  Purpose:                                                       */
81949757Smarc /*                                                                 */
82049757Smarc /*  Dummy stop routine.                                            */
82149757Smarc /*                                                                 */
82249757Smarc /*  Call:           xxstop(tp, flag)                               */
82349757Smarc /*  Argument:       tp:    pointer to tty structure                */
82449757Smarc /*                  flag:  indicates                               */
82549757Smarc /*  Returns:        none                                           */
82649757Smarc /*  Called by:      none                                           */
82749757Smarc /*                                                                 */
82849757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
82949757Smarc /*ARGSUSED*/
83049757Smarc xxstop(tp, flag)
83149757Smarc struct tty     *tp;
83249757Smarc int             flag;
83349757Smarc {
83449757Smarc }
83549757Smarc 
83649757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
83749757Smarc /*%%                        XXSELECT()                           %%*/
83849757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
83949757Smarc /*                                                                 */
84049757Smarc /*  Purpose:                                                       */
84149757Smarc /*                                                                 */
84249757Smarc /*  Circumvent bug in our bastardized design which causes ttselect */
84349757Smarc /*  to fail.							   */
84449757Smarc /*                                                                 */
84549757Smarc /*  Call:           xxselect(dev, rw)                              */
84649757Smarc /*  Argument:       dev:   device                                  */
84749757Smarc /*                  rw:    read or write indicator                 */
84849757Smarc /*  Returns:        0 or 1                                         */
84949757Smarc /*  Called by:      none                                           */
85049757Smarc /*                                                                 */
85149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
85249757Smarc 
xxselect(dev,rw)85349757Smarc xxselect(dev, rw)
85449757Smarc dev_t           dev;
85549757Smarc int             rw;
85649757Smarc {
85749757Smarc #ifdef	DDADEBUG
85849757Smarc     int unit = UNIT(dev);
85949757Smarc     if (DDADBCH(102, unit))
86049757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) select()\n", unit DDAELOG;
86149757Smarc #endif  DDADEBUG
86249757Smarc 
86349757Smarc     return (ttselect(MAJLINE(dev), rw));
86449757Smarc }
86549757Smarc 
86649757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
86749757Smarc /*%%                                                             %%*/
86849757Smarc /*%%                   LOCAL  FUNCTIONS                          %%*/
86949757Smarc /*%%                                                             %%*/
87049757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
87149757Smarc 
87249757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
87349757Smarc /*%%                      X29_SUPR()                             %%*/
87449757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
87549757Smarc /*                                                                 */
87649757Smarc /*  Purpose:                                                       */
87749757Smarc /*                                                                 */
87849757Smarc /*       This routine processes received supervisor messages.      */
87949757Smarc /*       Depending on the message type, the appropriate action is  */
88049757Smarc /*       taken.                                                    */
88149757Smarc /*                                                                 */
88249757Smarc /*  Call:              x29_supr(ds, p)                             */
88349757Smarc /*  Arguments:         ds:  pointer to dev control block struct    */
88449757Smarc /*                     p:   pointer to a character array           */
88549757Smarc /*                              containing the supervisor message  */
88649757Smarc /*  Returns:           nothing                                     */
88749757Smarc /*  Called by:         dda_supr()                                  */
88849757Smarc /*                                                                 */
88949757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
89049757Smarc 
89149757Smarc PRIVATE void
x29_supr(ds,p)89249757Smarc x29_supr(ds, p)
89349757Smarc struct dda_softc *ds;
89449757Smarc u_char          p[];
89549757Smarc {
89649757Smarc     register struct dda_cb *dc;
89749757Smarc     register struct tty *tp;
89849757Smarc     register int    lcn;
89949757Smarc     int   	    maxlcn;
90049757Smarc     int		    line;
90149757Smarc 
90249757Smarc #ifdef DDADEBUG
90349757Smarc     if (DDADBCH(103, ds->dda_if.if_unit)) {
90449757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) x29_supr()\n", ds->dda_if.if_unit
90549757Smarc 	DDAELOG;
90649757Smarc     }
90749757Smarc #endif  DDADEBUG
90849757Smarc 
90949757Smarc     switch (p[0]) {
91049757Smarc     case LINE_STATUS:		/* link status msg */
91149757Smarc     case RESTART:		/* restart received */
91249757Smarc     case RSTRT_ACK:		/* restart ack */
91349757Smarc     case STATRESP:		/* Statistics Response from FEP */
91449757Smarc 	DMESG(ds->dda_if.if_unit, 98, (DDALOG(LOG_ERR)
91549757Smarc 		"dda%d:(x29) x29_supr: unexpected message type\n",
91649757Smarc 		ds->dda_if.if_unit DDAELOG));
91749757Smarc 	break;
91849757Smarc     case ANSWER:		/* call answered */
91949757Smarc 	lcn = p[1] / 2;
92049757Smarc 	dc = &(ds->dda_cb[lcn]);
92149757Smarc 	if (dc->dc_state == LC_CALL_PENDING) {	/* if a call pending */
92249757Smarc 	    decode_answer(p, dc);
92349757Smarc 	    dc->dc_state = LC_DATA_IDLE;	/* set state */
92449757Smarc 	    dc->dc_flags = DC_X29;
92549757Smarc 	    line = dc->dc_line;			/* which line are we? */
92649757Smarc #ifdef DDADEBUG
92749757Smarc 	    if (DDADBCH(114, ds->dda_if.if_unit)) {
92849757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) x29_supr: answer: line=%d\n",
92949757Smarc 			ds->dda_if.if_unit, line
93049757Smarc 		DDAELOG;
93149757Smarc 	    }
93249757Smarc #endif  DDADEBUG
93349757Smarc 
93449757Smarc 	    if (line == -1) {				/* fubar! */
93549757Smarc 		DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
93649757Smarc 		    "dda%d:(x29) x29_supr: answer: line was -1, VC 0x%x\n",
93749757Smarc 		    ds->dda_if.if_unit, p[1] DDAELOG));
93849757Smarc 	    }
93949757Smarc 
94049757Smarc 	    xx_padinfo[line].p_state = PS_PAD;
94149757Smarc 	    xxstart(&xx_tty[line]);
94249757Smarc 	} else {
94349757Smarc 	    DMESG(ds->dda_if.if_unit, 108, (DDALOG(LOG_ERR)
94449757Smarc 		"dda%d:(x29) x29_supr: unexpected answer on LCN %d\n",
94549757Smarc 		ds->dda_if.if_unit, lcn DDAELOG));
94649757Smarc 	}
94749757Smarc 	if (LOG_CALLS) {
94849757Smarc 	    DDALOG(LOG_INFO) "dda%d:(x29) LCN %d: connected\n",
94949757Smarc 			     ds->dda_if.if_unit, lcn
95049757Smarc 	    DDAELOG;
95149757Smarc 	}
95249757Smarc 	break;
95349757Smarc 
95449757Smarc     case RING:			/* incoming call */
95549757Smarc 	if (decode_ring(p)) {
95649757Smarc 	    /* find a free lcn associated with a XX_HOST open */
95749757Smarc 	    dc = &ds->dda_cb[1];
95849757Smarc 	    maxlcn = nddach[ds->dda_if.if_unit];
95949757Smarc 	    for (lcn = 1; lcn <= maxlcn; lcn++) {
96049757Smarc 		if (dc->dc_state == LC_IDLE && dc->dc_flags & DC_X29W)
96149757Smarc 		    break;
96249757Smarc 		dc++;
96349757Smarc 	    }
96449757Smarc 	    if (lcn > maxlcn) {				/* if no free lcn's */
96549757Smarc 		if (LOG_BUSY) {
96649757Smarc 		    DDALOG(LOG_ERR)
96749757Smarc 			"dda%d:(x29) no free X29W lcns, call rejected, vc=0x%x\n",
96849757Smarc 			ds->dda_if.if_unit, p[1]
96949757Smarc 		    DDAELOG;
97049757Smarc 		}
97149757Smarc 		send_supr(ds, CLEARVC, p[2], 0);	/* clear call */
97249757Smarc 		break;					/* exit case */
97349757Smarc 	    }
97449757Smarc 
97549757Smarc 	    /* got a good lcn, now use it */
97649757Smarc 
97749757Smarc #ifdef DDADEBUG
97849757Smarc 	    if (DDADBCH(103, ds->dda_if.if_unit)) {
97949757Smarc 		DDALOG(LOG_ERR) "dda%d:(x29) supr_msg: call from 0x%0x\n",
98049757Smarc 		       ds->dda_if.if_unit, (u_long) dc->dc_inaddr.s_addr
98149757Smarc 		DDAELOG;
98249757Smarc 	    }
98349757Smarc #endif DDADEBUG
98449757Smarc 
98549757Smarc 	    dc->dc_state = LC_DATA_IDLE;	/* set state */
98649757Smarc 	    dc->dc_pktsizein = 0;
98749757Smarc 	    dc->dc_pktsizeout = 0;
98849757Smarc 	    dc->dc_wsizein = 0;
98949757Smarc 	    dc->dc_wsizeout = 0;
99049757Smarc 	    dc->dc_flags = DC_X29;
99149757Smarc 	    send_supr(ds, ANSWER, lcn * 2, p[2]);	/* send answer */
99249757Smarc 	    if (LOG_CALLS) {
99349757Smarc 		DDALOG(LOG_INFO) "dda%d:(x29) Call accepted LCN %d\n",
99449757Smarc 	  		         ds->dda_if.if_unit, dc->dc_lcn
99549757Smarc 		DDAELOG;
99649757Smarc 	    }
99749757Smarc 
99849757Smarc 	    line = dc->dc_line;
99949757Smarc 
100049757Smarc #ifdef DDADEBUG
100149757Smarc 	    if (DDADBCH(114, ds->dda_if.if_unit)) {
100249757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) x29_supr: ring: line=%d\n",
100349757Smarc 			ds->dda_if.if_unit, line
100449757Smarc 		DDAELOG;
100549757Smarc 	    }
100649757Smarc #endif  DDADEBUG
100749757Smarc 
100849757Smarc 	    if (line == -1) {				/* fubar! */
100949757Smarc 		DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
101049757Smarc 		    "dda%d:(x29) x29_supr: ring: line was -1, VC 0x%x\n",
101149757Smarc 		    ds->dda_if.if_unit, p[1] DDAELOG));
101249757Smarc 		break;
101349757Smarc 	    }
101449757Smarc 
101549757Smarc 	    tp = &xx_tty[line];
101649757Smarc 	    xx_padinfo[line].p_state = PS_XFR;
101749757Smarc 	    wakeup((caddr_t) &tp->t_rawq);
101849757Smarc 	    tp->t_state |= TS_CARR_ON;
101949757Smarc #if ACC_ULTRIX > 00
102049757Smarc 	    tp->t_state &= ~TS_ONDELAY;
102149757Smarc #endif
102249757Smarc 	    /* I would prefer to wait a bit before sending this */
102349757Smarc 	    send_x29_param_msg(ds, dc, SET_PAD,
102449757Smarc 			       x29_callin_setparams,
102549757Smarc 			       sizeof(x29_callin_setparams));
102649757Smarc 	} else {		/* bad decode */
102749757Smarc 	    send_supr(ds, CLEARVC, p[2], 0);	/* clear call */
102849757Smarc 	    DMESG(ds->dda_if.if_unit, 100, (DDALOG(LOG_ERR)
102949757Smarc 		"dda%d:(x29) Bad decode, call REJECTED VC 0x%x\n",
103049757Smarc 		ds->dda_if.if_unit, p[1] DDAELOG));
103149757Smarc 	}
103249757Smarc 	break;
103349757Smarc 
103449757Smarc     case CLEARLC:		/* clear by LCN */
103549757Smarc 	lcn = p[1] / 2;		/* get LCN */
103649757Smarc 	dc = &(ds->dda_cb[lcn]);
103749757Smarc 	if (dc->dc_state != LC_CLR_PENDING) {	/* if no clear pending */
103849757Smarc 	    send_supr(ds, CLEARLC, p[1], 0);	/* ack the clear */
103949757Smarc 	}
104049757Smarc 	if (dc->dc_state == LC_CALL_PENDING)	/* call is cleared */
104149757Smarc 	    DMESG(ds->dda_if.if_unit, 101, (DDALOG(LOG_ERR)
104249757Smarc 	    	"dda%d:(x29) Call cleared LCN %d (%x %x)\n",
104349757Smarc 	        ds->dda_if.if_unit, dc->dc_lcn, p[2], p[4] DDAELOG));
104449757Smarc 
104549757Smarc 	hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_IDLE);
104649757Smarc 	dc->dc_state = LC_IDLE;
104749757Smarc 	dc->dc_timer = TMO_OFF;	/* stop timer */
104849757Smarc 	dc->dc_wsizein = dc->dc_wsizeout = 0;
104949757Smarc 	dc->dc_pktsizein = dc->dc_pktsizeout = 0;
105049757Smarc 	abort_io(ds->dda_if.if_unit, lcn);
105149757Smarc 	xx_tp_hangup(ds, dc);	/* will clear flags */
105249757Smarc 	break;
105349757Smarc 
105449757Smarc     case CLEARVC:		/* clear by VCN */
105549757Smarc 	send_supr(ds, CLEARVC, p[1], 0);	/* send clear ack */
105649757Smarc 	if (LOG_CALLS) {
105749757Smarc 	    DDALOG(LOG_INFO)
105849757Smarc 		"dda%d:(x29) Network cleared VC %x (%x %x)\n",
105949757Smarc 	        ds->dda_if.if_unit, p[1], p[2], p[4]
106049757Smarc 	    DDAELOG;
106149757Smarc 	}
106249757Smarc 	break;
106349757Smarc 
106449757Smarc     case RESET:		/* X25 reset */
106549757Smarc 	send_supr(ds, RESET_ACK, p[1], 0);	/* send reset ack */
106649757Smarc 	abort_io(ds->dda_if.if_unit, (int) p[1] / 2);
106749757Smarc 	DMESG(ds->dda_if.if_unit, 102, (DDALOG(LOG_ERR)
106849757Smarc 	    "dda%d:(x29) X25 RESET on LCN %d (%x %x)\n",
106949757Smarc 	    ds->dda_if.if_unit, p[1] / 2, p[2], p[4] DDAELOG));
107049757Smarc 	break;
107149757Smarc 
107249757Smarc     case INTERRUPT:		/* X25 interrupt */
107349757Smarc #ifdef INDICATE_BREAK_ON_INTERRUPT
107449757Smarc 	lcn  = p[1] / 2;
107549757Smarc 	dc   = &(ds->dda_cb[lcn]);
107649757Smarc 
107749757Smarc 	line = dc->dc_line;
107849757Smarc 
107949757Smarc 	if (line == -1) {				/* fubar! */
108049757Smarc 	    DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
108149757Smarc 		"dda%d:(x29) x29_supr: break: line was -1, VC 0x%x\n",
108249757Smarc 		ds->dda_if.if_unit, p[1] DDAELOG));
108349757Smarc 	    break;
108449757Smarc 	}
108549757Smarc 
108649757Smarc 	tp   = &xx_tty[line];
108749757Smarc 
108849757Smarc 	if (tp->t_flags & RAW)
108949757Smarc 	    c = 0;
109049757Smarc 	else
109149757Smarc #if ACC_ULTRIX >= 30
109249757Smarc 	    c = tp->c_cc[VINTR];/* else make it the interrupt */
109349757Smarc #else
109449757Smarc 	    c = tp->t_intrc;	/* else make it the interrupt */
109549757Smarc #endif
109649757Smarc #if NBK > 0
109749757Smarc 	if (tp->t_line == NETLDISC) {
109849757Smarc 	    BKINPUT(c, tp);
109949757Smarc 	} else
110049757Smarc #endif
110149757Smarc 	    (*linesw[tp->t_line].l_rint) (c, tp);
110249757Smarc 	/* send_supr (ds, INTR_ACK, p[1], 0); 	not needed -- done by FE */
110349757Smarc #endif
110449757Smarc 	break;
110549757Smarc 
110649757Smarc     case INTR_ACK:
110749757Smarc 	/* quietly drop the acknowledgement */
110849757Smarc 	break;
110949757Smarc     default:
111049757Smarc 	DMESG(ds->dda_if.if_unit, 104, (DDALOG(LOG_ERR)
111149757Smarc 	    "dda%d:(x29) supervisor error (%x %x %x %x)\n",
111249757Smarc 	    ds->dda_if.if_unit, p[0], p[1], p[2], p[3] DDAELOG));
111349757Smarc     }
111449757Smarc }
111549757Smarc 
111649757Smarc 	/* hangup any attached processes */
111749757Smarc PRIVATE void
xx_tp_hangup(ds,dc)111849757Smarc xx_tp_hangup(ds, dc)
111949757Smarc struct dda_softc *ds;
112049757Smarc register struct dda_cb *dc;
112149757Smarc {
112249757Smarc     register struct tty *tp;
112349757Smarc     register padinfo    *pp;
112449757Smarc     register int         line;
112549757Smarc 
112649757Smarc     line = dc->dc_line;
112749757Smarc 
112849757Smarc     if (line == -1) {				/* fubar! */
112949757Smarc 	DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
113049757Smarc 	    "dda%d:(x29) xx_tp_hangup: line was -1\n",
113149757Smarc 	    ds->dda_if.if_unit DDAELOG));
113249757Smarc 	return;
113349757Smarc     }
113449757Smarc 
113549757Smarc     tp   = &xx_tty[line];
113649757Smarc     pp   = &xx_padinfo[line];
113749757Smarc 
113849757Smarc     if (pp->p_flow != P_NOBLOCK) {	/* currently blocked? */
113949757Smarc 	register struct hdx_chan *hc;
114049757Smarc 	hc = (struct hdx_chan *) & dc->dc_rchan;
114149757Smarc 	dda_rrq(ds, hc);	/* make sure we hang a read */
114249757Smarc     }
114349757Smarc     pp->p_flow = P_NOBLOCK;
114449757Smarc     tp->t_state &= ~(TS_CARR_ON | TS_ASLEEP | TS_BUSY);
114549757Smarc     ttyflush(tp, FREAD | FWRITE);
114649757Smarc     gsignal(tp->t_pgrp, SIGHUP);
114749757Smarc     gsignal(tp->t_pgrp, SIGCONT);
114849757Smarc     tp->t_state &= ~TS_ASLEEP;
114949757Smarc     wakeup((caddr_t) &tp->t_outq);
115049757Smarc     xxmode[line] = MODE_UNUSED;
115149757Smarc     tp->t_addr = (caddr_t) NULL;
115249757Smarc     pp->p_state = PS_IDLE;
115349757Smarc     if (pp->p_mchsav) {
115449757Smarc 	m_freem(pp->p_mchsav);
115549757Smarc 	pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
115649757Smarc     }
115749757Smarc     dc->dc_flags &= ~(DC_X29 | DC_X29W);	/* release to others */
115849757Smarc }
115949757Smarc 
116049757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
116149757Smarc /*%%                      X29_DATA()                             %%*/
116249757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
116349757Smarc /*                                                                 */
116449757Smarc /*  Purpose:                                                       */
116549757Smarc /*                                                                 */
116649757Smarc /*    This routine is called when a data channel I/O completes.    */
116749757Smarc /*    If the completion was for a write, an attempt is made to     */
116849757Smarc /*    start output on the next packet waiting for output on that   */
116949757Smarc /*    LCN.  If the completion was for a read, the received packet  */
117049757Smarc /*    is sent to the IP input queue (if no error) and another read */
117149757Smarc /*    is started on the LCN.                                       */
117249757Smarc /*                                                                 */
117349757Smarc /*  Call:              x29_data(ds, hc, cc, cnt)                   */
117449757Smarc /*  Argument:          ds:  device control block                   */
117549757Smarc /*                     hc:  half duplex channel control block      */
117649757Smarc /*                     cc:   Mailbox I/O completion status         */
117749757Smarc /*                     cnt:  byte count                            */
117849757Smarc /*  Returns:           nothing                                     */
117949757Smarc /*  Called by:         ddainta()                                   */
118049757Smarc /*                                                                 */
118149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
118249757Smarc 
118349757Smarc #define QBIT	0x80
118449757Smarc 
118549757Smarc PRIVATE void
x29_data(ds,hc,cc,cnt,subcc)118649757Smarc x29_data(ds, hc, cc, cnt, subcc)
118749757Smarc register struct dda_softc *ds;
118849757Smarc register struct hdx_chan *hc;
118949757Smarc int             cc,
119049757Smarc                 cnt,
119149757Smarc                 subcc;
119249757Smarc {
119349757Smarc     register struct dda_cb *dc = &(ds->dda_cb[hc->hc_chan / 2]);
119449757Smarc     register struct tty *tp;
119549757Smarc 
119649757Smarc #ifdef DDADEBUG
119749757Smarc     if (DDADBCH(104, ds->dda_if.if_unit)) {
119849757Smarc  	DDALOG(LOG_DEBUG)
119949757Smarc 	    "dda%d:(x29) x29_data: chan=%x cc=%x cnt=%x subcc=%x\n",
120049757Smarc 	    ds->dda_if.if_unit, hc->hc_chan, cc, cnt, subcc
120149757Smarc 	DDAELOG;
120249757Smarc     }
120349757Smarc #endif DDADEBUG
120449757Smarc 
120549757Smarc     if (hc->hc_chan & 0x01) {	/* if write, fire up next output */
120649757Smarc #ifdef DDADEBUG
120749757Smarc 	dc->dc_out_t = TMO_OFF;	/* turn off output completion timer */
120849757Smarc #endif
120949757Smarc 
121049757Smarc 	if ((hc->hc_func != DDAABT) && (hc->hc_curr = hc->hc_curr->m_next))
121149757Smarc 	    dda_wrq(ds, hc, 0);
121249757Smarc 	else {
121349757Smarc 	    /* it is abort | no more data left */
121449757Smarc 	    char            qbit_indicator;
121549757Smarc 	    qbit_indicator = hc->hc_mbuf->m_dat[MLEN - 1];
121649757Smarc 	    m_freem(hc->hc_mbuf);
121749757Smarc 	    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
121849757Smarc 	    if (hc->hc_func == DDAABT) {
121949757Smarc 		hc->hc_func &= ~DDAABT;
122049757Smarc 		hc->hc_inv &= ~INVALID_MBUF;
122149757Smarc 	    } else
122249757Smarc 		ds->dda_if.if_opackets++;
122349757Smarc 	    dc->dc_flags &= ~DC_OBUSY;
122449757Smarc 
122549757Smarc 	    if (qbit_indicator == QBIT) {	/* Q-bit packet? */
122649757Smarc 		dda_start(ds, dc);		/* restart output */
122749757Smarc 	    } else {
122849757Smarc 		tp = &xx_tty[dc->dc_line];
122949757Smarc 		tp->t_state &= ~TS_BUSY;
123049757Smarc 		xxstart(tp);	/* restart tty output */
123149757Smarc 	    }
123249757Smarc 	}
123349757Smarc 
123449757Smarc 	/* it's a packet coming in from the front end to the host */
123549757Smarc     } else {
123649757Smarc #ifdef DDADEBUG
123749757Smarc 	dc->dc_flags &= ~DC_IPEND;
123849757Smarc #endif
123949757Smarc 	hc = &dc->dc_rchan;
124049757Smarc 
124149757Smarc #ifdef DDADEBUG
124249757Smarc 	if (DDADBCH(105, ds->dda_if.if_unit)) {
124349757Smarc 	    u_char         *p;
124449757Smarc 	    DDALOG(LOG_DEBUG) "dda%d:(x29) ", ds->dda_if.if_unit DDAELOG;
124549757Smarc 	    p = mtod(hc->hc_curr, u_char *);
124649757Smarc 	    prt_bytes(ds->dda_if.if_unit, "received data", p, (cnt < 64 ? cnt : 64));
124749757Smarc 	}
124849757Smarc 	if (DDADBCH(106, ds->dda_if.if_unit)) {
124949757Smarc 	    DDALOG(LOG_DEBUG)
125049757Smarc 		"dda%d:(x29) x29_data: read complete mbuf=%x curr=%x\n",
125149757Smarc 		ds->dda_if.if_unit, hc->hc_mbuf, hc->hc_curr
125249757Smarc 	    DDAELOG;
125349757Smarc 	}
125449757Smarc #endif DDADEBUG
125549757Smarc 
125649757Smarc 	if (dc->dc_state != LC_DATA_IDLE) {
125749757Smarc 	    m_freem(hc->hc_mbuf);	/* toss the packet, lcn is dead */
125849757Smarc 	    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
125949757Smarc 	} else if (cc == DDAIOCOK || (cc == DDAIOCOKP && !(subcc & QBIT))) {
126049757Smarc 	/* Queue up I/O completion OK transfers and I/O OK with more data
126149757Smarc 	 * pending transfers (as long as it's not a Qbit message).
126249757Smarc 	 * This algorythm operates differently than the IP handler due
126349757Smarc 	 * to the fact that we don't need to wait for the entire X.25
126449757Smarc 	 * packet to arrive on the host before we assemble it.  To do
126549757Smarc 	 * so should be OK,  but unfortunately it seems some brain-dead
126649757Smarc 	 * PAD's generate packets with the M-bit set if they have more
126749757Smarc 	 * data in their internal buffers.  This can cause the system
126849757Smarc 	 * to burn up mbufs waiting for us to finally receive a packet
126949757Smarc 	 * with the M-bit not set.  However, we should hold up on processing
127049757Smarc 	 * packets with both the Q-bit and the M-bit set until we receive
127149757Smarc 	 * the entire Q-bit message.  If we get 30k Q-bit packets, we will
127249757Smarc 	 * die, but that is obscenely absurd in the first place.
127349757Smarc 	 * (sigh)	-- pst 7-19-89
127449757Smarc 	 */
127549757Smarc 
127649757Smarc #ifdef DDADEBUG
127749757Smarc 	    if (DDADBCH(107, ds->dda_if.if_unit)) {
127849757Smarc 		DDALOG(LOG_DEBUG)
127949757Smarc 		    "dda%d:(x29) x29_data: chan=%x DDAIOCOK\n",
128049757Smarc 		    ds->dda_if.if_unit, hc->hc_chan
128149757Smarc 		DDAELOG;
128249757Smarc 	    }
128349757Smarc #endif DDADEBUG
128449757Smarc 	    hc->hc_curr->m_len += cnt;	/* update byte count */
128549757Smarc 
128649757Smarc 	    ds->dda_if.if_ipackets++;
128749757Smarc 	    /* HANDLE THE DATA HERE */
128849757Smarc 	    if (subcc & QBIT) {
128949757Smarc 		int             len;
129049757Smarc 		char           *mcp;
129149757Smarc 		mcp = mtod(hc->hc_curr, char *);
129249757Smarc 		len = hc->hc_curr->m_len;
129349757Smarc 
129449757Smarc #ifdef DDADEBUG
129549757Smarc 		if (DDADBCH(108, ds->dda_if.if_unit))
129649757Smarc 		    prt_bytes(ds->dda_if.if_unit,
129749757Smarc 			      "(x29) Qbit:", mcp, (len < 64 ? len : 64));
129849757Smarc #endif DDADEBUG
129949757Smarc 
130049757Smarc 		if (*mcp == BREAK_INDIC) {	/* Break indication? */
130149757Smarc 		    register struct tty *tp;
130249757Smarc 		    if (x29_break_reply_is_required(mcp, len)) {
130349757Smarc 			/* tell pad to stop discarding output */
130449757Smarc 			send_x29_param_msg(ds, dc, SET_PAD,
130549757Smarc 					   x29_break_ack_params, 2);
130649757Smarc 		    }
130749757Smarc 		    hc->hc_curr->m_len = 1;	/* change data to single byte */
130849757Smarc 		    tp = &xx_tty[dc->dc_line];
130949757Smarc 		    if (tp->t_flags & RAW)	/* if port is in raw mode, */
131049757Smarc 			*mcp = 0;	/* make the byte a null */
131149757Smarc 		    else
131249757Smarc #if ACC_ULTRIX >= 30
131349757Smarc 			*mcp = tp->t_cc[VINTR];	/* else make it the interrupt */
131449757Smarc #else
131549757Smarc 			*mcp = tp->t_intrc;	/* else make it the interrupt */
131649757Smarc #endif
131749757Smarc 		    x29_dhandle(ds, dc, 0);
131849757Smarc 		    return;
131949757Smarc 		} else if (*mcp & READ_PAD) {
132049757Smarc 		    if (len == 1)	/* just a message, no params? */
132149757Smarc 			send_x29_param_msg(ds, dc, PAR_INDICATION,
132249757Smarc 					   x29_callout_params,
132349757Smarc 					   sizeof(x29_callout_params));
132449757Smarc 		    else
132549757Smarc 			send_x29_param_msg(ds, dc, PAR_INDICATION, mcp + 1, len - 1);
132649757Smarc 		    m_freem(hc->hc_mbuf);
132749757Smarc 		    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
132849757Smarc 		} else {
132949757Smarc 		    m_freem(hc->hc_mbuf);
133049757Smarc 		    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
133149757Smarc 		}
133249757Smarc 	    } else {			/* not Qbit data, process normally */
133349757Smarc 		x29_dhandle(ds, dc, 0);
133449757Smarc 		return;
133549757Smarc 	    }
133649757Smarc 	} else if (cc == DDAIOCOKP) {	/* good completion, more data pending */
133749757Smarc 	    hc->hc_curr->m_len += cnt;
133849757Smarc 	} else {			/* toss packet */
133949757Smarc 	    m_freem(hc->hc_mbuf);
134049757Smarc 	    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
134149757Smarc 	}
134249757Smarc 	/* hang a new data read */
134349757Smarc #ifdef DDADEBUG
134449757Smarc 	dc->dc_flags |= DC_IPEND;
134549757Smarc #endif
134649757Smarc 	dda_rrq(ds, hc);
134749757Smarc     }
134849757Smarc }
134949757Smarc 
135049757Smarc /* this routine copies chars from the dc_rchan mbuf to the upper
135149757Smarc  * level software.  If all the characters are read then the mbuf is
135249757Smarc  * freed and a new read is hung on the channel.
135349757Smarc  *
135449757Smarc  * This routine is called from below by the int A handler and from above
135549757Smarc  * by the device read routine.
135649757Smarc  */
135749757Smarc 
135849757Smarc PRIVATE void
x29_dhandle(ds,dc,restart)135949757Smarc x29_dhandle(ds, dc, restart)
136049757Smarc register struct dda_softc *ds;
136149757Smarc register struct dda_cb *dc;
136249757Smarc int             restart;
136349757Smarc {
136449757Smarc     register struct tty *tp;
136549757Smarc     register struct hdx_chan *hc;
136649757Smarc     register padinfo *pp;
136749757Smarc     u_char         *cp,
136849757Smarc                     c;
136949757Smarc     struct mbuf    *m2,
137049757Smarc                    *m;
137149757Smarc     int             s,
137249757Smarc                     line;
137349757Smarc     register int    j;
137449757Smarc     static int      recurse = 0;
137549757Smarc 
137649757Smarc     s = splimp();
137749757Smarc 
137849757Smarc     if (recurse) {	/* don't allow ourselves to be called recursively */
137949757Smarc 	splx(s);
138049757Smarc 	return;
138149757Smarc     } else
138249757Smarc 	recurse = 1;
138349757Smarc 
138449757Smarc     hc = (struct hdx_chan *) &dc->dc_rchan;
138549757Smarc 
138649757Smarc     line = dc->dc_line;
138749757Smarc 
138849757Smarc     tp = &xx_tty[line];
138949757Smarc     pp = &xx_padinfo[line];
139049757Smarc 
139149757Smarc     if (restart) {		/* trying to restart input? */
139249757Smarc 	j  = pp->p_flow;
139349757Smarc 	m  = pp->p_mchsav;
139449757Smarc 	m2 = pp->p_msav;
139549757Smarc 
139649757Smarc #ifdef DDADEBUG
139749757Smarc 	if (DDADBCH(109, ds->dda_if.if_unit)) {
139849757Smarc 	    DDALOG(LOG_DEBUG)
139949757Smarc 		"dda%d:(x29) flow restart [%d] in %x\n",
140049757Smarc 		ds->dda_if.if_unit, j, m
140149757Smarc 	    DDAELOG;
140249757Smarc 	}
140349757Smarc #endif DDADEBUG
140449757Smarc 
140549757Smarc     } else {
140649757Smarc 	j = P_NOBLOCK;
140749757Smarc 	m2 = m = hc->hc_mbuf;	/* que mbuf chain */
140849757Smarc     }
140949757Smarc 
141049757Smarc     if (m == 0) {
141149757Smarc 	DMESG(ds->dda_if.if_unit, 105, (DDALOG(LOG_ERR)
141249757Smarc 		"dda%d:(x29) x29_dhandle: null mbuf\n",
141349757Smarc 		ds->dda_if.if_unit DDAELOG));
141449757Smarc 	hc->hc_mbuf = hc->hc_curr = (struct mbuf *) NULL;
141549757Smarc 	dda_rrq(ds, hc);
141649757Smarc 	goto out;
141749757Smarc     }
141849757Smarc     while (m2) {
141949757Smarc 	cp = mtod(m2, u_char *);
142049757Smarc 	for (; j < m2->m_len; j++) {
142149757Smarc 	    c = cp[j] & INPUT_PARITY_MASK;
142249757Smarc 	    if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG - 2)
142349757Smarc 		if (!ttbreakc(c, tp))
142449757Smarc 		    continue;	/* dump the character */
142549757Smarc #if NBK > 0
142649757Smarc 	    if (tp->t_line == NETLDISC) {
142749757Smarc 		BKINPUT(c, tp);
142849757Smarc 	    } else
142949757Smarc #endif
143049757Smarc 		(*linesw[tp->t_line].l_rint) (c, tp);
143149757Smarc 
143249757Smarc 
143349757Smarc 	    /* Block further input iff: Current input > threshold AND input
143449757Smarc 	     * is available to user program */
143549757Smarc 
143649757Smarc 	    if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG / 4 &&
143749757Smarc 		((tp->t_flags & (RAW | CBREAK)) || (tp->t_canq.c_cc > 0))) {
143849757Smarc #ifdef DDADEBUG
143949757Smarc 		if (DDADBCH(109, ds->dda_if.if_unit)) {
144049757Smarc 		    DDALOG(LOG_DEBUG)
144149757Smarc 			"dda%d:(x29) flow on [%d] in %x of %d\n",
144249757Smarc 			ds->dda_if.if_unit, j, m2, m2->m_len
144349757Smarc 		    DDAELOG;
144449757Smarc 		}
144549757Smarc #endif DDADEBUG
144649757Smarc 		pp->p_flow = j + 1;
144749757Smarc 		pp->p_msav = m2;
144849757Smarc 		pp->p_mchsav = m;
144949757Smarc 		if (restart == 0)
145049757Smarc 		    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) NULL;
145149757Smarc 		goto out;
145249757Smarc 	    }
145349757Smarc 	}
145449757Smarc 	m2 = m2->m_next;
145549757Smarc 	j = P_NOBLOCK;
145649757Smarc     }
145749757Smarc     if (restart)
145849757Smarc 	pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
145949757Smarc 
146049757Smarc     m_freem(m);
146149757Smarc     hc->hc_mbuf = hc->hc_curr = (struct mbuf *) NULL;
146249757Smarc     pp->p_flow  = P_NOBLOCK;
146349757Smarc 
146449757Smarc #ifdef DDADEBUG
146549757Smarc     dc->dc_flags |= DC_IPEND;
146649757Smarc #endif
146749757Smarc 
146849757Smarc     dda_rrq(ds, hc);
146949757Smarc 
147049757Smarc out:
147149757Smarc     recurse = 0;
147249757Smarc     splx(s);
147349757Smarc }
147449757Smarc 
147549757Smarc PRIVATE void
xx_qbit_msg(tp,unit,msg)147649757Smarc xx_qbit_msg(tp, unit, msg)
147749757Smarc register struct tty *tp;
147849757Smarc int             unit;
147949757Smarc char           *msg;
148049757Smarc {
148149757Smarc     register struct dda_cb *dc;
148249757Smarc     register struct dda_softc *ds;
148349757Smarc     int             s;
148449757Smarc 
148549757Smarc     ds = &dda_softc[unit];
148649757Smarc     dc = (struct dda_cb *) tp->t_addr;
148749757Smarc     s = splimp();
148849757Smarc 
148949757Smarc #ifdef DDADEBUG
149049757Smarc     if (DDADBCH(110, unit)) {
149149757Smarc 	DDALOG(LOG_DEBUG)
149249757Smarc 	    "dda%d:(x29) xx_qbit_msg: %d %d %d\n",
149349757Smarc 	    unit, msg[0], msg[1], msg[2]
149449757Smarc 	DDAELOG;
149549757Smarc     }
149649757Smarc #endif DDADEBUG
149749757Smarc 
149849757Smarc     if (msg[1] < (MLEN - 4))
149949757Smarc 	send_x29_param_msg(ds, dc, msg[0], msg + 2, msg[1]);
150049757Smarc     splx(s);
150149757Smarc }
150249757Smarc 
150349757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
150449757Smarc /*%%                        XXCNTL()                             %%*/
150549757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
150649757Smarc /*                                                                 */
150749757Smarc /*  Purpose:                                                       */
150849757Smarc /*                                                                 */
150949757Smarc /*  Do modem control functions on a line.                          */
151049757Smarc /*                                                                 */
151149757Smarc /*  Call:           xxcntl(tp, c, d)                               */
151249757Smarc /*  Argument:       tp:   pointer to tty structure                 */
151349757Smarc /*                  c:    function code                            */
151449757Smarc /*                  unit: for unit number                          */
151549757Smarc /*  Returns:        none                                           */
151649757Smarc /*  Called by:      xxopen()                                       */
151749757Smarc /*                  xxclose()                                      */
151849757Smarc /*                  xxread()                                       */
151949757Smarc /*                  xxint()                                        */
152049757Smarc /*                                                                 */
152149757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
152249757Smarc 
152349757Smarc PRIVATE void
xxcntl(tp,c,unit)152449757Smarc xxcntl(tp, c, unit)
152549757Smarc register struct tty *tp;
152649757Smarc int             c,
152749757Smarc                 unit;
152849757Smarc {
152949757Smarc     register struct dda_cb *dc;
153049757Smarc     register struct dda_softc *ds;
153149757Smarc     register padinfo *pp;
153249757Smarc     int             s,
153349757Smarc                     l;
153449757Smarc 
153549757Smarc     l = tp - xx_tty;
153649757Smarc     ds = &dda_softc[unit];
153749757Smarc     pp = &xx_padinfo[l];
153849757Smarc     s = splimp();
153949757Smarc 
154049757Smarc #ifdef DDADEBUG
154149757Smarc     if (DDADBCH(111, unit)) {
154249757Smarc 	DDALOG(LOG_DEBUG)
154349757Smarc 	    "dda%d:(x29) xxcntl: tp=0x%x line=%d\n", unit, tp, l
154449757Smarc 	DDAELOG;
154549757Smarc     }
154649757Smarc #endif DDADEBUG
154749757Smarc 
154849757Smarc     switch (c) {
154949757Smarc     case XX_C_PAD:
155049757Smarc 	if (tp->t_addr)
155149757Smarc 	    break;
155249757Smarc 	if (dc = find_free_lcn(ds)) { /* race against locate_x25_lcn */
155349757Smarc 	    dc->dc_flags = DC_X29;
155449757Smarc 	    dc->dc_line = l;
155549757Smarc 	    pp->p_state = PS_COM;
155649757Smarc 	    tp->t_addr = (caddr_t) dc;
155749757Smarc 	    tp->t_flags &= ~ECHO;
155849757Smarc 	    pp->p_flow = P_NOBLOCK;
155949757Smarc 	    pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
156049757Smarc 	    pp->p_idx = 0;
156149757Smarc 	    pp->p_line[0] = '\0';
156249757Smarc 	} else
156349757Smarc 	    tp->t_addr = (caddr_t) NULL;
156449757Smarc 	break;
156549757Smarc     case XX_C_HOST:
156649757Smarc 	if (tp->t_addr)
156749757Smarc 	    break;
156849757Smarc 	if (dc = find_free_lcn(ds)) { /* race against locate_x25_lcn */
156949757Smarc 	    dc->dc_flags = DC_X29W;
157049757Smarc 	    dc->dc_line = l;
157149757Smarc 	    pp->p_state = PS_WAIT;
157249757Smarc 	    pp->p_flow = P_NOBLOCK;
157349757Smarc 	    pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
157449757Smarc 	    tp->t_addr = (caddr_t) dc;
157549757Smarc 	} else
157649757Smarc 	    tp->t_addr = (caddr_t) NULL;
157749757Smarc 	break;
157849757Smarc     case XX_C_CLOSE:
157949757Smarc 	pp->p_state = PS_IDLE;
158049757Smarc 	if (pp->p_mchsav) {
158149757Smarc 	    m_freem(pp->p_mchsav);
158249757Smarc 	    pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
158349757Smarc 	}
158449757Smarc 	dc = (struct dda_cb *) tp->t_addr;
158549757Smarc 	if (dc == 0)
158649757Smarc 	    break;
158749757Smarc 	if (pp->p_flow != P_NOBLOCK) {	/* currently blocked? */
158849757Smarc 	    register struct hdx_chan *hc;
158949757Smarc 	    hc = (struct hdx_chan *) &dc->dc_rchan;
159049757Smarc 	    dda_rrq(ds, hc);		/* make sure we hang a read */
159149757Smarc 	}
159249757Smarc #ifdef	DDADEBUG
159349757Smarc 	if (DDADBCH(111, unit)) {
159449757Smarc 	    static char *st[] = { "lcn down", "lcn restart", "idle",
159549757Smarc 				  "call pending", "data idle", "clear pending"
159649757Smarc 				};
159749757Smarc 	    DDALOG(LOG_DEBUG)
159849757Smarc 		"dda%d:(x29) xxcntl: close state: %s\n", unit, st[dc->dc_state]
159949757Smarc 	    DDAELOG;
160049757Smarc 	}
160149757Smarc #endif DDADEBUG
160249757Smarc 
160349757Smarc 	if (dc->dc_state == LC_DATA_IDLE || dc->dc_state == LC_CALL_PENDING)
160449757Smarc 	    clear_lcn(ds, dc);	/* send clear & set state to clr_pending */
160549757Smarc 				/* timers will convert it to LC_IDLE later */
160649757Smarc 
160749757Smarc #ifdef	DDADEBUG
160849757Smarc 	else
160949757Smarc 	    if (DDADBCH(111, unit)) {
161049757Smarc 		DDALOG(LOG_DEBUG)
161149757Smarc 		    "dda%d:(x29) xxcntl: warning: state not data_idle\n", unit
161249757Smarc 		DDAELOG;
161349757Smarc 	    }
161449757Smarc #endif
161549757Smarc 
161649757Smarc 	dc->dc_flags &= ~(DC_X29 | DC_X29W);	/* release to others */
161749757Smarc 	tp->t_addr = (caddr_t) NULL;
161849757Smarc 	break;
161949757Smarc     case XX_C_BREAK:
162049757Smarc 
162149757Smarc 	/* really should look at X.3 parameters to decide if an interrupt
162249757Smarc 	 * packet should be sent. instead, we take an action which assumes
162349757Smarc 	 * PAD parameter 7 has value 21 */
162449757Smarc 	dc = (struct dda_cb *) tp->t_addr;
162549757Smarc 	send_supr(ds, INTERRUPT, dc->dc_lcn * 2, 0);
162649757Smarc 	send_x29_param_msg(ds, dc, BREAK_INDIC, 0, 0);
162749757Smarc 	break;
162849757Smarc     }
162949757Smarc     splx(s);
163049757Smarc }
163149757Smarc 
163249757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
163349757Smarc /*%%                     X29_INIT()                              %%*/
163449757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
163549757Smarc /*                                                                 */
163649757Smarc /*  Purpose:                                                       */
163749757Smarc /*                                                                 */
163849757Smarc /*  Software reset, clear lines.                                   */
163949757Smarc /*                                                                 */
164049757Smarc /*  Call:           x29_init(unit, active);                        */
164149757Smarc /*  Argument:       unit:  ACP _XX device                          */
164249757Smarc /*  Returns:        none                                           */
164349757Smarc /*  Called by:      none                                           */
164449757Smarc /*                                                                 */
164549757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
164649757Smarc 
164749757Smarc PRIVATE void
x29_init(unit,active)164849757Smarc x29_init(unit, active)
164949757Smarc int             unit,
165049757Smarc                 active;
165149757Smarc {
165249757Smarc     register int    i;
165349757Smarc     register padinfo *pp;
165449757Smarc 
165549757Smarc #ifdef	DDADEBUG
165649757Smarc     if (DDADBCH(113, unit)) {
165749757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) x29_init() active=%d\n",
165849757Smarc 			  unit, active
165949757Smarc 	DDAELOG;
166049757Smarc     }
166149757Smarc #endif  DDADEBUG
166249757Smarc 
166349757Smarc     if (active)
166449757Smarc 	xxclear(unit);
166549757Smarc     else {
166649757Smarc 	for (i = 0; i < XXLPERBRD; i++) {
166749757Smarc 	    xx_tty[unit * XXLPERBRD + i].t_state = PS_IDLE;
166849757Smarc 	    pp = &xx_padinfo[unit * XXLPERBRD + i];
166949757Smarc 	    pp->p_state = PS_IDLE;
167049757Smarc 	    pp->p_flow  = P_NOBLOCK;
167149757Smarc 	    pp->p_msav  = pp ->p_mchsav = (struct mbuf *) NULL;
167249757Smarc 	}
167349757Smarc     }
167449757Smarc }
167549757Smarc 
167649757Smarc PRIVATE void
xxclear(unit)167749757Smarc xxclear(unit)
167849757Smarc int             unit;
167949757Smarc {
168049757Smarc     register struct tty *tp;
168149757Smarc     register struct dda_softc *ds;
168249757Smarc     register struct dda_cb *dc;
168349757Smarc     int             i,
168449757Smarc                     state;
168549757Smarc 
168649757Smarc     ds = &dda_softc[unit];
168749757Smarc     for (i = 0, tp = &xx_tty[unit * XXLPERBRD]; i < XXLPERBRD; i++, tp++) {
168849757Smarc 	state = tp->t_state;
168949757Smarc #ifdef	DDADEBUG
169049757Smarc 	if (DDADBCH(112, unit) && state) {
169149757Smarc 	    DDALOG(LOG_DEBUG)
169249757Smarc 		"dda%d:(x29) xxclear: line=%d pgrp=%d state=%d\n",
169349757Smarc 		unit, i, tp->t_pgrp, state
169449757Smarc 	    DDAELOG;
169549757Smarc 	}
169649757Smarc #endif  DDADEBUG
169749757Smarc 	if (state & TS_WOPEN) {
169849757Smarc 	    tp->t_state &= ~TS_WOPEN;
169949757Smarc 	    wakeup(&tp->t_rawq);
170049757Smarc 	}
170149757Smarc 	if (tp->t_state) {
170249757Smarc 	    dc = (struct dda_cb *) tp->t_addr;
170349757Smarc 	    if (dc) {
170449757Smarc 		xx_tp_hangup(ds, dc);
170549757Smarc 		dc->dc_line = -1;	/* break correspondence */
170649757Smarc 	    }
170749757Smarc 	}
170849757Smarc     }
170949757Smarc }
171049757Smarc 
171149757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
171249757Smarc /*%%                        XXSHOW()                             %%*/
171349757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
171449757Smarc /*                                                                 */
171549757Smarc /*  Purpose:                                                       */
171649757Smarc /*                                                                 */
171749757Smarc /*      Show status of each active unit                            */
171849757Smarc /*                                                                 */
171949757Smarc /*  Call:           xxshow()                                       */
172049757Smarc /*  Argument:       none		                           */
172149757Smarc /*  Returns:        none                                           */
172249757Smarc /*  Called by:      none                                           */
172349757Smarc /*                                                                 */
172449757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
172549757Smarc 
172649757Smarc PRIVATE void
xxshow()172749757Smarc xxshow()
172849757Smarc {
172949757Smarc     register struct tty *tp;
173049757Smarc     register padinfo    *pp;
173149757Smarc     int                  unit,
173249757Smarc                          i;
173349757Smarc     static char	        *st[] = { "idle", " com", " pad", "wait", "xfer" };
173449757Smarc 
173549757Smarc 
173649757Smarc     for (unit = 0; unit < (NDDA < XXBOARDS ? NDDA : XXBOARDS); unit++) {
173749757Smarc 	uprintf("\nACP5250/6250 X29 driver: state of unit %d -\n", unit);
173849757Smarc 	uprintf("line\tstate\tlcn\tflow\ttstate\ttflags\n");
173949757Smarc 
174049757Smarc 	for (i = 0, tp = &xx_tty[unit * XXLPERBRD]; i < XXLPERBRD; i++, tp++) {
174149757Smarc 	    if (tp->t_state) {
174249757Smarc 		pp = &xx_padinfo[i];
174349757Smarc 		uprintf("%d:\t%s\t%d\t%d\t%x\t%x\n", i, st[pp->p_state],
174449757Smarc 		       (struct dda_cb *) (tp->t_addr) - dda_softc[unit].dda_cb,
174549757Smarc 		       pp->p_flow, tp->t_state, tp->t_flags);
174649757Smarc 	    }
174749757Smarc 	}
174849757Smarc     }
174949757Smarc     uprintf("remaining lines free\n");
175049757Smarc }
175149757Smarc 
175249757Smarc /******************************************************************************
175349757Smarc  *                           PAD CODE
175449757Smarc  ******************************************************************************/
175549757Smarc /* PADCHARUP - Pass a character up towards the user */
175649757Smarc #define PADCHARUP(c,tp) (*linesw[(tp)->t_line].l_rint) ((c), (tp))
175749757Smarc 
175849757Smarc PRIVATE void
xxpadhandle(ds,tp,pi)175949757Smarc xxpadhandle(ds, tp, pi)
176049757Smarc struct dda_softc *ds;
176149757Smarc struct tty     *tp;		/* pointer to relevant tty structure */
176249757Smarc padinfo        *pi;		/* pointer to relevant padinfo structure */
176349757Smarc {
176449757Smarc     register int    i;
176549757Smarc     register char   c;
176649757Smarc     register struct dda_cb *dc;
176749757Smarc     int             nch;
176849757Smarc     char            tbuf[CBSIZE];	/* CBSIZE is number of char in a
176949757Smarc 					 * cblock */
177049757Smarc     nch = q_to_b(&tp->t_outq, tbuf, CBSIZE);
177149757Smarc 
177249757Smarc     /* handle characters in command state. Its OK if were slow here because
177349757Smarc      * there is a person on the other end of the discussion */
177449757Smarc     dc = (struct dda_cb *) tp->t_addr;
177549757Smarc     for (i = 0; i < nch; i++) {
177649757Smarc 	if (pi->p_idx >= P_LINELEN) {
177749757Smarc 	    xxpadmsg("\r\ncommand too long\r\n@", tp);
177849757Smarc 	    pi->p_idx = 0;
177949757Smarc 	    return;
178049757Smarc 	}
178149757Smarc 	c = pi->p_line[pi->p_idx] = tbuf[i] & INPUT_PARITY_MASK;
178249757Smarc 	if (c == '\r' || c == '\n') {
178349757Smarc 	    PADCHARUP('\r', tp);
178449757Smarc 	    PADCHARUP('\n', tp);
178549757Smarc 	    pi->p_line[pi->p_idx] = '\0';
178649757Smarc 	    if (dc && dc->dc_state != LC_IDLE) {
178749757Smarc 		xxpadmsg("cannot call, line is in transition\r\n", tp);
178849757Smarc 		if (dc && dc->dc_state == LC_CALL_PENDING)
178949757Smarc 		    xxpadmsg("previous call still pending\r\n", tp);
179049757Smarc 	    } else if (xxpadparse(ds, pi, tp) == 0)
179149757Smarc 		PADCHARUP('@', tp);
179249757Smarc 	    pi->p_idx = 0;
179349757Smarc 	} else if (c == '\b' || c == '\177') {
179449757Smarc 	    if (pi->p_idx) {
179549757Smarc 		pi->p_idx--;
179649757Smarc 		xxpadmsg("\b \b", tp);
179749757Smarc 	    }
179849757Smarc 	} else {
179949757Smarc 	    pi->p_idx++;
180049757Smarc 	    PADCHARUP(c, tp);
180149757Smarc 	}
180249757Smarc     }
180349757Smarc }
180449757Smarc 
180549757Smarc PRIVATE int
xxpadparse(ds,pi,tp)180649757Smarc xxpadparse(ds, pi, tp)
180749757Smarc struct dda_softc *ds;
180849757Smarc padinfo        *pi;
180949757Smarc struct tty     *tp;
181049757Smarc {
181149757Smarc     char           *p = pi->p_line;
181249757Smarc 
181349757Smarc     if (*p == 'c' || *p == 'C') {	/* connect command */
181449757Smarc 	for (p++; *p == ' '; *p++);
181549757Smarc 	if (*p < '0' || *p > '9')
181649757Smarc 	    xxpadmsg("???\r\n", tp);
181749757Smarc 	else			/* place a call */
181849757Smarc 	    return xxpadcall(ds, p, tp);
181949757Smarc     } else if (*p)
182049757Smarc 	xxpadmsg("invalid command\r\n", tp);
182149757Smarc     return 0;
182249757Smarc }
182349757Smarc 
182449757Smarc PRIVATE int
xxpadcall(ds,addr,tp)182549757Smarc xxpadcall(ds, addr, tp)
182649757Smarc struct dda_softc *ds;
182749757Smarc char           *addr;
182849757Smarc struct tty     *tp;
182949757Smarc {
183049757Smarc     register int    i = 0;
183149757Smarc     struct in_addr  in;
183249757Smarc 
183349757Smarc     while (addr[i]) {
183449757Smarc 	if (addr[i] < '0' || addr[i] > '9') {
183549757Smarc 	    xxpadmsg("invalid address\r\n", tp);
183649757Smarc 	    return 0;
183749757Smarc 	}
183849757Smarc 	i++;
183949757Smarc     }
184049757Smarc     ddacb_called_addr[0] = i;
184149757Smarc     bcopy(addr, ddacb_called_addr + 1, i);
184249757Smarc     ddacb_user_data[0] = (u_char) 0;	/* no user data for now */
184349757Smarc     in.s_addr = 0;
184449757Smarc     return make_x25_call(ds, (struct dda_cb *) tp->t_addr, in, X25_PROTO_X29);
184549757Smarc }
184649757Smarc 
184749757Smarc PRIVATE void
xxpadmsg(s,tp)184849757Smarc xxpadmsg(s, tp)
184949757Smarc char           *s;
185049757Smarc struct tty     *tp;
185149757Smarc {
185249757Smarc     while (*s) {
185349757Smarc 	PADCHARUP(*s, tp);
185449757Smarc 	s++;
185549757Smarc     }
185649757Smarc }
185749757Smarc 
185849757Smarc /*
185949757Smarc  * This routine is used to respond to
186049757Smarc  * READ_PARAMS and SET_READ_PARAMS requests, and also
186149757Smarc  * to send out a SET_PARAMS request for incoming calls.
186249757Smarc  * The outgoing pad supports NO parameters.
186349757Smarc  */
send_x29_param_msg(ds,dc,type,msg,len)186449757Smarc send_x29_param_msg(ds, dc, type, msg, len)
186549757Smarc register struct dda_cb *dc;
186649757Smarc register struct dda_softc *ds;
186749757Smarc x29_pad_pair   *msg;
186849757Smarc {
186949757Smarc     struct mbuf    *m;
187049757Smarc     u_char         *p;
187149757Smarc     short           i;
187249757Smarc     register struct ifqueue *oq;
187349757Smarc     m = 0;			/* Allocate an mbuf to stuff the chars into */
187449757Smarc     MGET(m, M_DONTWAIT, MT_DATA);
187549757Smarc     if (m == 0) {
187649757Smarc 	DMESG(ds->dda_if.if_unit, 106, (DDALOG(LOG_ERR)
187749757Smarc 		"dda%d:(x29) couldn't get mbuf for QBIT message\n",
187849757Smarc 		ds->dda_if.if_unit DDAELOG));
187949757Smarc 	return;
188049757Smarc     }
188149757Smarc     m->m_dat[MLEN - 1] = QBIT;	/* set Q-bit */
188249757Smarc     p = mtod(m, u_char *);
188349757Smarc     len = len / 2;
188449757Smarc     *p++ = type;
188549757Smarc     if (type == PAR_INDICATION) {	/* our pad supports NO parameters */
188649757Smarc 	for (i = 0; i < len; i++) {
188749757Smarc 	    *p++ = msg[i].ref | 0x80;	/* set invalid bit */
188849757Smarc 	    *p++ = 1;		/* not implemented */
188949757Smarc 	}
189049757Smarc     } else {			/* BREAK_INDIC, SET_PAD to ack break */
189149757Smarc 	for (i = 0; i < len; i++) {
189249757Smarc 	    *p++ = msg[i].ref;
189349757Smarc 	    *p++ = msg[i].val;
189449757Smarc 	}
189549757Smarc     }
189649757Smarc     m->m_len = 1 + 2 * len;
189749757Smarc     oq = &(dc->dc_oq);		/* point to output queue */
189849757Smarc     if (IF_QFULL(oq)) {		/* if q full */
189949757Smarc 	IF_DROP(oq);		/* drop the data */
190049757Smarc 	m_freem(m);
190149757Smarc 	ds->dda_if.if_collisions++;	/* for netstat display */
190249757Smarc     } else {
190349757Smarc 	IF_ENQUEUE(oq, m);	/* otherwise queue it */
190449757Smarc 	dda_start(ds, dc);	/* and try to output */
190549757Smarc     }
190649757Smarc }
190749757Smarc 
190849757Smarc PRIVATE int
x29_break_reply_is_required(mcp,len)190949757Smarc x29_break_reply_is_required(mcp, len)
191049757Smarc char           *mcp;
191149757Smarc int             len;
191249757Smarc {
191349757Smarc     mcp++;			/* skip over break indication msg */
191449757Smarc     while (len > 1) {		/* while there are parameters left, */
191549757Smarc 	if ((*mcp == 8) && (mcp[1] == 1))	/* paramter 8 set to 1? */
191649757Smarc 	    return 1;		/* yes */
191749757Smarc 	mcp += 2;
191849757Smarc 	len -= 2;
191949757Smarc     }
192049757Smarc     return 0;
192149757Smarc }
192249757Smarc 
192349757Smarc /*
192449757Smarc  * Ultrix 3.0 removed the old ttbreakc() kernel routine when moving to
192549757Smarc  * a posix compliant driver.  Here it is again, (for our local use only!!!)
192649757Smarc  *
192749757Smarc  */
192849757Smarc #if ACC_ULTRIX >= 30
192949757Smarc static int
ttbreakc(c,tp)193049757Smarc ttbreakc(c, tp)
193149757Smarc register        c;
193249757Smarc register struct tty *tp;
193349757Smarc {
193449757Smarc     return (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOF] ||
193549757Smarc 	    c == tp->t_cc[VEOL2] || c == '\r' && (tp->t_flags & CRMOD));
193649757Smarc }
193749757Smarc #endif
193849757Smarc 
193949757Smarc 
194049757Smarc /*
194149757Smarc Revision History:
194249757Smarc 
194349757Smarc 09-Jun-1988: Unknown (Brad?)
194449757Smarc 	Initial implementation.
194549757Smarc 15-Feb-1989: Paul Traina
194649757Smarc 	Fixed point bug in send_x29_prm_msg
194749757Smarc 08-Mar-1989: Steve Johnson
194849757Smarc 	Fixed bug in xx_flow logic
194949757Smarc 24-May-1989: Paul Traina
195049757Smarc 	Upgraded for Ultrix 3.0
195149757Smarc 28-May-1989: Paul Traina
195249757Smarc 	Added more driver intelligence to disable pad durring call pending
195349757Smarc 31-May-1989: Paul Traina
195449757Smarc 	Added flexible mapping for # of boards per unit
195549757Smarc 04-Jun-1989: Paul Traina
195649757Smarc 	Fixed driver to dequeue Q-bit X29 packets from the mbuf chain properly.
195749757Smarc 19-Jun-1989: Paul Traina
195849757Smarc 	Fixed previous fix-- will need to go over if-elseif logic more
195949757Smarc 	carefully to make sure we're doing the right thing.  It should be
196049757Smarc 	recoded.
196149757Smarc 	Modernized entire debug code suite, changed xxshow functionality to
196249757Smarc 	use the uprintf() kernel call to display data on user's terminal for
196349757Smarc 	the xxshow hack.
196449757Smarc 12-Jul-1989: Paul Traina
196549757Smarc 	Changed format of some debug messages.  Removed LOCAL_VOID in
196649757Smarc 	favor of PRIVATE routine to aid in debugging.  Simplified some
196749757Smarc 	chunky logic.
196849757Smarc 18-Jul-1989: Paul Traina
196949757Smarc 	Flipped search order for finding a free X29W lcn at RING time.
197049757Smarc 	Moved the dc_key.ttyline field out of the union and made it dc_line.
197149757Smarc 	This fixed the Dartmouth singleuser bug.
197249757Smarc 19-Jul-1989: Paul Traina
197349757Smarc 	Changed the packet decode logic in x29_data to immediately process
197449757Smarc 	packets with more data pending (i.e. the M-bit) right away, instead
197549757Smarc 	of queuing them up.  (Note: it still queues up Q-bit packets)  This
197649757Smarc 	may fix the Dartmouth mbuf problem with blasting uploads.
197749757Smarc 27-Jul-1989: Paul Traina
197849757Smarc 	Removed 8-bit strip in x29_dhandle.
197949757Smarc 01-Aug-1989: Paul Traina
198049757Smarc 	Added additional two parameters to make_x25_call for userdata/length
198149757Smarc 	for merge with new pad software.
198249757Smarc 02-Aug-1989: Paul Traina
198349757Smarc 	Reinserted 8-bit strip on data received from the net.  (uses
198449757Smarc 	PARITY_MASK define for easy change).
198549757Smarc 	Fixed forward declaration of ttbreakc().
198649757Smarc 	Improved readability of xxshow output.
198749757Smarc 	Removed "super" pad code.
198849757Smarc 	Modified ps_state to be a real state variable.
198949757Smarc 03-Aug-1989: Paul Traina
199049757Smarc 	Reversed earlier change to xxselect which didn't pass major #.
199149757Smarc 	Modified xxshow output to not use %nd which isn't supported in BSD.
199249757Smarc 28-Aug-1989: Paul Traina
199349757Smarc 	Changed parameters of make_x25_call -- plug user data field directly.
199449757Smarc 14-Nov-1989: Paul Traina
199549757Smarc 	Added support for Ultrix 3.1 which uses HUPCL instead of HUPCLS
199649757Smarc 	because of that stupid termio interface (sigh).
199749757Smarc 16-Nov-1989: Paul Traina
199849757Smarc 	Changed parity mask to input_parity_mask, added output_parity_mask.
199949757Smarc */
2000