xref: /csrg-svn/sys/vax/if/ACC/driver/if_x29.c (revision 49757)
1*49757Smarc /*
2*49757Smarc  *
3*49757Smarc  *     X.29 option for dda driver for UNIX and Ultrix
4*49757Smarc  *      ________________________________________________________
5*49757Smarc  *     /                                                        \
6*49757Smarc  *    |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
7*49757Smarc  *    |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
8*49757Smarc  *    |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
9*49757Smarc  *    |       AAAA AAAA      CCCC              CCCC              |
10*49757Smarc  *    |      AAAA   AAAA     CCCC              CCCC              |
11*49757Smarc  *    |     AAAA     AAAA    CCCC              CCCC              |
12*49757Smarc  *    |    AAAA       AAAA   CCCC              CCCC              |
13*49757Smarc  *    |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
14*49757Smarc  *    |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
15*49757Smarc  *    | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
16*49757Smarc  *     \________________________________________________________/
17*49757Smarc  *
18*49757Smarc  *      Copyright (c) 1987 by Advanced Computer Communications
19*49757Smarc  *      720 Santa Barbara Street, Santa Barbara, California  93101
20*49757Smarc  *      (805) 963-9431
21*49757Smarc  *
22*49757Smarc  * File:
23*49757Smarc  *      if_x29.c
24*49757Smarc  *
25*49757Smarc  * Author:
26*49757Smarc  *
27*49757Smarc  * Project:
28*49757Smarc  *      Development of PAD on 6250 software.
29*49757Smarc  *
30*49757Smarc  * Function:
31*49757Smarc  *      To enable network connections on ACP_XX to communicate with UNIX.
32*49757Smarc  *
33*49757Smarc  * Components:
34*49757Smarc  *      - files if_x29.c
35*49757Smarc  *
36*49757Smarc  * Configuration Entry:
37*49757Smarc  *
38*49757Smarc  *      device dda0 at uba? csr 0166740 vector ddainta ddaintb
39*49757Smarc  *
40*49757Smarc  * Usage Notes:
41*49757Smarc  *
42*49757Smarc  *      - make devices in /dev and edit /etc/ttys for those x29
43*49757Smarc  *        devices which you want in your configuration
44*49757Smarc  *
45*49757Smarc  * System Notes:
46*49757Smarc  *
47*49757Smarc  *       Refer to the installation instructions, readme.txt, which
48*49757Smarc  *       are included on the driver distribution medium.
49*49757Smarc  *
50*49757Smarc  * Revision History at end of file
51*49757Smarc  */
52*49757Smarc 
53*49757Smarc /*
54*49757Smarc  *	For efficiency, it is a good idea to modify XXBOARDS when using
55*49757Smarc  *	less than 4 boards with the X29 option.  If using more than 32
56*49757Smarc  *	lines per board, you should modify XXBOARDS, XXLPERBRD, LOG2_XXBOARDS
57*49757Smarc  *	and LOG2_XXLPERBRD.
58*49757Smarc  *
59*49757Smarc  *	Minor numbers are laid out as follows (by default):
60*49757Smarc  *		(MSB) PBBLLLLL (LSB)
61*49757Smarc  *	Where P is a flag to determine if the line is outbound (pad) or
62*49757Smarc  *	inbound (tty).  BB is the board number (0-3), and LLLLL is the
63*49757Smarc  *	X29 line on a board (0-31).  Some customers may need more than
64*49757Smarc  *	32 lines/board.  If there are less than 2 boards,  one may shift
65*49757Smarc  *	the break-point between lines and boards:
66*49757Smarc  *
67*49757Smarc  *	up to 4 boards, 32 lines/board	(default)
68*49757Smarc  *		(MSB) PBBLLLLL (LSB)
69*49757Smarc  *			XXBOARDS  = 4,   LOG2_XXBOARDS  = 2
70*49757Smarc  *			XXLPERBRD = 32,	 LOG2_XXLPERBRD = 5
71*49757Smarc  *	up to 2 boards, 64 lines/board:
72*49757Smarc  *		(MSB) PBLLLLLL (LSB)
73*49757Smarc  *			XXBOARDS  = 2,   LOG2_XXBOARDS  = 1
74*49757Smarc  *			XXLPERBRD = 64,  LOG2_XXLPERBRD = 6
75*49757Smarc  *	only 1 board, 128 (actually, 126, as 126 = max svc):
76*49757Smarc  *		(MSB) PLLLLLLL (LSB)
77*49757Smarc  *			XXBOARDS  = 1,   LOG2_XXBOARDS  = 0
78*49757Smarc  *			XXLPERBRD = 128, LOG2_XXLPERBRD = 7
79*49757Smarc  *
80*49757Smarc  *	(obviously, these are all powers of two)
81*49757Smarc  */
82*49757Smarc 
83*49757Smarc #define	XXBOARDS	4	/* # boards running x29 */
84*49757Smarc #define	LOG2_XXBOARDS	2	/* # bits of board info */
85*49757Smarc 
86*49757Smarc #define XXLPERBRD	32	/* # lines per board */
87*49757Smarc #define	LOG2_XXLPERBRD	5	/* # bits of line info */
88*49757Smarc 
89*49757Smarc /*
90*49757Smarc  * If you require an 8-bit data path and have no parity misconfigurations,
91*49757Smarc  * you may change PARITY_MASKs to 0377.  This will leave parity stripping
92*49757Smarc  * to the ttdriver.  However,  the ttdriver won't strip parity when in
93*49757Smarc  * raw mode (e.g. at the Password: prompt),  so one symptom of a parity
94*49757Smarc  * misconfiguration is that users can't login (CR gets received as 0x8D).
95*49757Smarc  */
96*49757Smarc 
97*49757Smarc #define	INPUT_PARITY_MASK  0177	/* strip off the 8th bit */
98*49757Smarc #define	OUTPUT_PARITY_MASK 0377	/* don't strip off the 8th bit */
99*49757Smarc 
100*49757Smarc /*
101*49757Smarc  * macro to translate a device number to the unit (i.e. ACP_n250)
102*49757Smarc  * with which it is associated and the port on said unit
103*49757Smarc  */
104*49757Smarc 
105*49757Smarc #define UNIT(x) ((minor(x) >> LOG2_XXLPERBRD) & LOG2_XXBOARDS)
106*49757Smarc 
107*49757Smarc #define LINE(x)	  (minor(x) & 0177)	/* index into line table */
108*49757Smarc #define XXSHOW(x) (minor(x) == 255)	/* special "show" device */
109*49757Smarc #define IS_PAD(x) (minor(x) & 0200)	/* msb is the pad/tty selector */
110*49757Smarc #define MAJLINE(x) ((x) & ~0x80)	/* major plus corrected minor # */
111*49757Smarc 
112*49757Smarc #define NXXLINES        (XXBOARDS * XXLPERBRD)	/* number of total x29 lines */
113*49757Smarc 
114*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
115*49757Smarc /*%%                                                             %%*/
116*49757Smarc /*%%                   LOCAL  FUNCTIONS                          %%*/
117*49757Smarc /*%%                                                             %%*/
118*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
119*49757Smarc 
120*49757Smarc PRIVATE void    xxcntl();
121*49757Smarc PRIVATE void    xxclear();
122*49757Smarc PRIVATE void    xxshow();
123*49757Smarc PRIVATE void    xxpadhandle();
124*49757Smarc PRIVATE int     xxpadparse();
125*49757Smarc PRIVATE int     xxpadcall();
126*49757Smarc PRIVATE void    xxpadmsg();
127*49757Smarc PRIVATE void	xx_qbit_msg();
128*49757Smarc PRIVATE void    xx_tp_hangup();
129*49757Smarc PRIVATE void    x29_init();
130*49757Smarc PRIVATE void    x29_dhandle();
131*49757Smarc PRIVATE int	x29_break_reply_is_required();
132*49757Smarc 
133*49757Smarc #if ACC_ULTRIX >= 30
134*49757Smarc static  int	ttbreakc();		/* always keep this private */
135*49757Smarc #endif
136*49757Smarc 
137*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
138*49757Smarc /*%%                                                             %%*/
139*49757Smarc /*%%                   LOCAL  VARIABLES                          %%*/
140*49757Smarc /*%%                                                             %%*/
141*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
142*49757Smarc 
143*49757Smarc #define SET_PAD		2
144*49757Smarc #define READ_PAD	4
145*49757Smarc #define SET_READ_PAD	6
146*49757Smarc #define PAR_INDICATION	0
147*49757Smarc #define INVITE_CLEAR	1
148*49757Smarc #define BREAK_INDIC	3
149*49757Smarc #define PAD_ERROR	5
150*49757Smarc 
151*49757Smarc /* command codes */
152*49757Smarc #define XX_C_BREAK	001
153*49757Smarc #define XX_C_PAD	002
154*49757Smarc #define XX_C_CLOSE	003
155*49757Smarc #define XX_C_HOST	004
156*49757Smarc 
157*49757Smarc struct tty      xx_tty[NXXLINES];	/* tty structures */
158*49757Smarc 
159*49757Smarc #define MODE_UNUSED 0			/* !just for sanity checks only! */
160*49757Smarc #define	MODE_HOST 1			/* port in host mode (incoming) */
161*49757Smarc #define	MODE_PAD  2			/* port in pad mode (outgoing) */
162*49757Smarc 
163*49757Smarc char            xxmode[NXXLINES];	/* mode of port */
164*49757Smarc 
165*49757Smarc int             xxstart();
166*49757Smarc 
167*49757Smarc typedef struct {
168*49757Smarc     char            ref;
169*49757Smarc     char            val;
170*49757Smarc } x29_pad_pair;
171*49757Smarc 
172*49757Smarc PRIVATE x29_pad_pair x29_break_ack_params[] =
173*49757Smarc {
174*49757Smarc  8, 0				/* ref 8 -- normal output to terminal */
175*49757Smarc };
176*49757Smarc 
177*49757Smarc PRIVATE x29_pad_pair x29_callout_params[] =
178*49757Smarc {
179*49757Smarc  1, 0				/* ref 1 -- no recall char */
180*49757Smarc };
181*49757Smarc 
182*49757Smarc PRIVATE x29_pad_pair x29_callin_setparams[] =
183*49757Smarc { /* these are the preferred paramters when calling in to Unix */
184*49757Smarc  2, 0,				/* ref 2 -- no echo */
185*49757Smarc  3, 127,			/* ref 3 -- forward data on any char */
186*49757Smarc  8, 0,				/* ref 8 -- normal data delivery to terminal */
187*49757Smarc  9, 0,				/* ref 9 -- no padding after carriage return */
188*49757Smarc  10, 0,				/* ref 10 -- no line folding */
189*49757Smarc  13, 0,				/* ref 13 -- no line feed after CR */
190*49757Smarc  15, 0				/* ref 15 -- no local edit */
191*49757Smarc };
192*49757Smarc 
193*49757Smarc /******************************************************************************
194*49757Smarc  *  PAD CONTROL INFORMATION AND DEFINITIONS
195*49757Smarc  ******************************************************************************/
196*49757Smarc 
197*49757Smarc /* definitions for the pad state field p_state */
198*49757Smarc #define PS_IDLE	0		/* not opened state */
199*49757Smarc #define PS_COM  1		/* the pad for this line is in command state */
200*49757Smarc #define PS_PAD  2		/* this line has data passing though the pad */
201*49757Smarc #define PS_WAIT	3		/* waiting state */
202*49757Smarc #define PS_XFR	4		/* data transfer state */
203*49757Smarc 
204*49757Smarc #define P_LINELEN	20
205*49757Smarc #define P_NOBLOCK	0
206*49757Smarc 
207*49757Smarc typedef struct padinfo {
208*49757Smarc     short           p_state;	/* pad state */
209*49757Smarc     char            p_line[P_LINELEN];	/* built up line */
210*49757Smarc     char            p_idx;	/* index into p_line */
211*49757Smarc     int		    p_flow;	/* index into mbuf when flow off,
212*49757Smarc 				   P_NOBLOCK if not flowed off */
213*49757Smarc     struct mbuf    *p_msav;	/* place to hang mbuf when flow controlled */
214*49757Smarc     struct mbuf    *p_mchsav;	/* place to save mbuf chain '' '' '' */
215*49757Smarc } padinfo;
216*49757Smarc padinfo         xx_padinfo[NXXLINES];
217*49757Smarc 
218*49757Smarc 
219*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
220*49757Smarc /*%%                                                             %%*/
221*49757Smarc /*%%                   GLOBAL ROUTINES                           %%*/
222*49757Smarc /*%%                                                             %%*/
223*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
224*49757Smarc 
225*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
226*49757Smarc /*%%                       XXOPEN()                              %%*/
227*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
228*49757Smarc /*                                                                 */
229*49757Smarc /*  Purpose:                                                       */
230*49757Smarc /*                                                                 */
231*49757Smarc /*  Open a line.                                                   */
232*49757Smarc /*                                                                 */
233*49757Smarc /*  Call:           xxopen(dev, flag)                              */
234*49757Smarc /*  Argument:       dev:   device                                  */
235*49757Smarc /*                  flag:  indicates type of open, "nonblocking"   */
236*49757Smarc /*                         "or block if in use"                    */
237*49757Smarc /*  Returns:        0 for success, else nonzero error code         */
238*49757Smarc /*  Called by:      kernel software software,  this routine is in  */
239*49757Smarc /*                  the cdevsw table                               */
240*49757Smarc /*                                                                 */
241*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
242*49757Smarc 
243*49757Smarc /*ARGSUSED*/
244*49757Smarc xxopen(dev, flag)
245*49757Smarc dev_t           dev;
246*49757Smarc int             flag;
247*49757Smarc {
248*49757Smarc     register struct tty *tp;
249*49757Smarc     register        d;
250*49757Smarc     register        s;
251*49757Smarc     int             unit,
252*49757Smarc                     i;
253*49757Smarc #if ACC_ULTRIX > 00
254*49757Smarc     int             inuse;	/* store inuse bit while sleeping */
255*49757Smarc #endif
256*49757Smarc 
257*49757Smarc     unit = UNIT(dev);
258*49757Smarc     d = LINE(dev);
259*49757Smarc 
260*49757Smarc     if (XXSHOW(dev)) {		/* minor device 255 */
261*49757Smarc 	xxshow();
262*49757Smarc 	return (EPIPE);
263*49757Smarc     }
264*49757Smarc 
265*49757Smarc     /* PST NOTE TO SELF: change the test as follows:
266*49757Smarc      *	make this d >= NXXLINES, then check to see if unit is present,
267*49757Smarc      *  Keep that sleep() in the thingy below, so we don't get bouncing
268*49757Smarc      *  gettys eating up cpu time.
269*49757Smarc      */
270*49757Smarc     if ((d >= NXXLINES))
271*49757Smarc 	return (ENXIO);
272*49757Smarc 
273*49757Smarc     /* wait for interface to come up */
274*49757Smarc     while (dda_softc[unit].dda_state != S_LINK_UP)
275*49757Smarc 	sleep(&dda_softc[unit].dda_state, TTIPRI);
276*49757Smarc 
277*49757Smarc     tp = &xx_tty[d];
278*49757Smarc     if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0)
279*49757Smarc 	return EBUSY;
280*49757Smarc 
281*49757Smarc     /* make sure the port isn't already open in a conflicting manner */
282*49757Smarc     /* i.e. can't open /dev/padJ0 and /dev/ttyJ0 at the same time */
283*49757Smarc     if (tp->t_state & (TS_WOPEN | TS_ISOPEN)) {
284*49757Smarc 	if ((IS_PAD(dev) && (xxmode[d] == MODE_HOST)) ||
285*49757Smarc 	    ((!IS_PAD(dev)) && (xxmode[d] == MODE_PAD)))
286*49757Smarc 	    return EBUSY;
287*49757Smarc     }
288*49757Smarc 
289*49757Smarc #ifdef	DDADEBUG
290*49757Smarc 	if (DDADBCH(96, unit)) {
291*49757Smarc 		DDALOG(LOG_DEBUG)
292*49757Smarc 		    "dda%d:(x29) open line %d flag %o in %s mode\n",
293*49757Smarc 		    unit, d, flag, (IS_PAD(dev) ? "pad" : "host")
294*49757Smarc 		DDAELOG;
295*49757Smarc 	}
296*49757Smarc #endif  DDADEBUG
297*49757Smarc 
298*49757Smarc     tp->t_oproc = xxstart;
299*49757Smarc     tp->t_state |= TS_WOPEN;
300*49757Smarc 
301*49757Smarc     /* if first open initialize state */
302*49757Smarc     if ((tp->t_state & TS_ISOPEN) == 0) {
303*49757Smarc 	ttychars(tp);
304*49757Smarc 
305*49757Smarc #if ACC_ULTRIX >= 30		/* posix compliant tty driver */
306*49757Smarc 	if (tp->t_cflag & CBAUD == 0) {
307*49757Smarc 	    tp->t_iflag = IGNPAR | ICRNL | IXON | IXANY | IXOFF;
308*49757Smarc 	    tp->t_oflag = OPOST | ONLCR;
309*49757Smarc 	    tp->t_cflag = B9600 | CS8 | CREAD | HUPCL;
310*49757Smarc 	    tp->t_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL;
311*49757Smarc 	    tp->t_line = 0;
312*49757Smarc 	}
313*49757Smarc #else				/* v7 tty driver */
314*49757Smarc 	if (tp->t_ispeed == 0) {
315*49757Smarc 	    tp->t_ispeed = B9600;
316*49757Smarc 	    tp->t_ospeed = B9600;
317*49757Smarc 	    tp->t_flags = CRMOD | ANYP;
318*49757Smarc 	}
319*49757Smarc #endif
320*49757Smarc 	xxparam(dev);
321*49757Smarc     }
322*49757Smarc     if (IS_PAD(dev)) {
323*49757Smarc 	tp->t_state |= TS_CARR_ON;
324*49757Smarc 	xxmode[d] = MODE_PAD;
325*49757Smarc 	xxcntl(tp, XX_C_PAD, unit);
326*49757Smarc     } else {
327*49757Smarc 	if ((tp->t_state & TS_CARR_ON) == 0) {
328*49757Smarc 	    xxmode[d] = MODE_HOST;
329*49757Smarc 	    xxcntl(tp, XX_C_HOST, unit);
330*49757Smarc 	    tp->t_flags |= ECHO;
331*49757Smarc #if ACC_ULTRIX < 31	/* on everything other than Ultrix 3.1 */
332*49757Smarc 	    /* on close tell ACP_XX to drop line */
333*49757Smarc 	    tp->t_state |= TS_HUPCLS;
334*49757Smarc #endif
335*49757Smarc 	}
336*49757Smarc     }
337*49757Smarc     /* if xxcntl did not get called (state had carrier off) or xxcntl's
338*49757Smarc      * search for a free lcn failed, then t_addr will be 0, so punt */
339*49757Smarc     if (tp->t_addr == 0) {
340*49757Smarc 	tp->t_pgrp = 0;
341*49757Smarc 	tp->t_state = 0;
342*49757Smarc 	xxmode[d] = MODE_UNUSED;
343*49757Smarc 	return (EBUSY);
344*49757Smarc     }
345*49757Smarc     xx_padinfo[d].p_flow = P_NOBLOCK;
346*49757Smarc     s = splimp();
347*49757Smarc 
348*49757Smarc #if ACC_ULTRIX > 00
349*49757Smarc     if (flag & O_NDELAY) {
350*49757Smarc 	if (!IS_PAD(dev))
351*49757Smarc 	    tp->t_state |= TS_ONDELAY;
352*49757Smarc     } else
353*49757Smarc #endif
354*49757Smarc 	while ((tp->t_state & TS_CARR_ON) == 0) {
355*49757Smarc 	    tp->t_state |= TS_WOPEN;
356*49757Smarc #if ACC_ULTRIX > 00
357*49757Smarc 	    inuse = tp->t_state & TS_INUSE;
358*49757Smarc #endif
359*49757Smarc 	    sleep(&tp->t_rawq, TTIPRI);
360*49757Smarc 
361*49757Smarc 	    /* wakeup came from xxclear */
362*49757Smarc 	    if ((tp->t_state & TS_WOPEN) == 0) {
363*49757Smarc 		splx(s);
364*49757Smarc 		return (EPIPE);
365*49757Smarc 	    }
366*49757Smarc #if ACC_ULTRIX > 00
367*49757Smarc 	    /* if port became "inuse" while we slept, return */
368*49757Smarc 	    if ((flag & O_BLKINUSE) && (!inuse) &&
369*49757Smarc 		(tp->t_state & TS_INUSE)) {
370*49757Smarc 		splx(s);
371*49757Smarc 		return (EALREADY);
372*49757Smarc 	    }
373*49757Smarc #endif
374*49757Smarc 	}
375*49757Smarc 
376*49757Smarc     splx(s);
377*49757Smarc     i = ((*linesw[tp->t_line].l_open) (dev, tp));
378*49757Smarc     if (tp->t_pgrp == 0)
379*49757Smarc 	tp->t_pgrp = u.u_procp->p_pid;
380*49757Smarc     return (i);
381*49757Smarc }
382*49757Smarc 
383*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
384*49757Smarc /*%%                       XXCLOSE()                             %%*/
385*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
386*49757Smarc /*                                                                 */
387*49757Smarc /*  Purpose:                                                       */
388*49757Smarc /*                                                                 */
389*49757Smarc /*  Close a line.                                                  */
390*49757Smarc /*                                                                 */
391*49757Smarc /*  Call:           xxclose(dev, flag)                             */
392*49757Smarc /*  Argument:       dev:   device                                  */
393*49757Smarc /*                  flag:  unused                                  */
394*49757Smarc /*  Returns:        nothing                                        */
395*49757Smarc /*  Called by:      kernel software,  this routine is in the	   */
396*49757Smarc /*		    cdevsw table                                   */
397*49757Smarc /*                                                                 */
398*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
399*49757Smarc 
400*49757Smarc /*ARGSUSED*/
401*49757Smarc xxclose(dev, flag)
402*49757Smarc dev_t           dev;
403*49757Smarc int             flag;
404*49757Smarc {
405*49757Smarc     register struct tty *tp;
406*49757Smarc     register        d;
407*49757Smarc     d = LINE(dev);
408*49757Smarc     tp = &xx_tty[d];
409*49757Smarc 
410*49757Smarc #ifdef	DDADEBUG
411*49757Smarc 	if (DDADBCH(97, UNIT(dev))) {
412*49757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) closing line %d\n", UNIT(dev), d
413*49757Smarc 		DDAELOG;
414*49757Smarc 	}
415*49757Smarc #endif  DDADEBUG
416*49757Smarc 
417*49757Smarc 	/* PST NOTE TO SELF:
418*49757Smarc 	 *	Add the 629 driver code for timing out the close below,
419*49757Smarc 	 *	because the line could be flowed off and it would hang
420*49757Smarc 	 * 	forever */
421*49757Smarc 
422*49757Smarc     (*linesw[tp->t_line].l_close) (tp);
423*49757Smarc 
424*49757Smarc #if ACC_ULTRIX >= 31
425*49757Smarc     if ((tp->t_cflag & HUPCL) || ((tp->t_state & TS_ISOPEN) == 0)) {
426*49757Smarc #else
427*49757Smarc     if ((tp->t_state & TS_HUPCLS) || ((tp->t_state & TS_ISOPEN) == 0)) {
428*49757Smarc #endif
429*49757Smarc 
430*49757Smarc #ifdef	DDADEBUG
431*49757Smarc 	if (DDADBCH(97, UNIT(dev))) {
432*49757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) close: tp->t_state = %x\n",
433*49757Smarc 				  UNIT(dev), tp->t_state
434*49757Smarc 		DDAELOG;
435*49757Smarc 	}
436*49757Smarc #endif  DDADEBUG
437*49757Smarc 
438*49757Smarc 	if (tp->t_state & TS_CARR_ON)
439*49757Smarc 	    xxcntl(tp, XX_C_CLOSE, UNIT(dev));
440*49757Smarc 	tp->t_state &= ~TS_CARR_ON;
441*49757Smarc 	xxmode[d] = MODE_UNUSED;
442*49757Smarc     }
443*49757Smarc     ttyclose(tp);
444*49757Smarc }
445*49757Smarc 
446*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
447*49757Smarc /*%%                       XXREAD()                              %%*/
448*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
449*49757Smarc /*                                                                 */
450*49757Smarc /*  Purpose:                                                       */
451*49757Smarc /*                                                                 */
452*49757Smarc /*  Read from a line.                                              */
453*49757Smarc /*                                                                 */
454*49757Smarc /*  Call:           xxread(dev, uio)                               */
455*49757Smarc /*  Argument:       dev:   device                                  */
456*49757Smarc /*                  uio:   pointer to uio structure                */
457*49757Smarc /*  Returns:        0 for success, else nonzero error code         */
458*49757Smarc /*  Called by:      kernel software,  this routine is in	   */
459*49757Smarc /*                  the cdevsw table                               */
460*49757Smarc /*                                                                 */
461*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
462*49757Smarc 
463*49757Smarc xxread(dev, uio)
464*49757Smarc dev_t           dev;
465*49757Smarc struct uio     *uio;
466*49757Smarc {
467*49757Smarc     register struct tty *tp;
468*49757Smarc     register int    l,
469*49757Smarc                     error;
470*49757Smarc 
471*49757Smarc     if (dda_softc[UNIT(dev)].dda_state != S_LINK_UP)
472*49757Smarc 	return (ENXIO);
473*49757Smarc 
474*49757Smarc     l = LINE(dev);
475*49757Smarc     tp = &xx_tty[l];
476*49757Smarc     error = (*linesw[tp->t_line].l_read)(tp, uio);
477*49757Smarc 
478*49757Smarc     if (xx_padinfo[l].p_flow != P_NOBLOCK) {	/* currently blocked? */
479*49757Smarc 	if (tp->t_flags & (RAW | CBREAK)) {	/* using raw q? */
480*49757Smarc 	    if (tp->t_rawq.c_cc < TTYHOG / 8) {	/* if rawq is low, then
481*49757Smarc 						 * it's time to unblock */
482*49757Smarc 		x29_dhandle(&dda_softc[UNIT(dev)],
483*49757Smarc 			    (struct dda_cb *) (tp->t_addr), 1);
484*49757Smarc 	    }
485*49757Smarc 	/* else cooked mode, different test */
486*49757Smarc 	/* canonical q empty? then it's time to unblock */
487*49757Smarc 	} else if (tp->t_canq.c_cc == 0) {
488*49757Smarc 	    x29_dhandle(&dda_softc[UNIT(dev)],
489*49757Smarc 			(struct dda_cb *) (tp->t_addr), 1);
490*49757Smarc 	}
491*49757Smarc     }
492*49757Smarc     return (error);
493*49757Smarc }
494*49757Smarc 
495*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
496*49757Smarc /*%%                       XXWRITE()                             %%*/
497*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
498*49757Smarc /*                                                                 */
499*49757Smarc /*  Purpose:                                                       */
500*49757Smarc /*                                                                 */
501*49757Smarc /*  Write on a line.                                               */
502*49757Smarc /*                                                                 */
503*49757Smarc /*  Call:           xxwrite(dev, uio)                              */
504*49757Smarc /*  Argument:       dev:   device                                  */
505*49757Smarc /*                  uio:   pointer to uio structure                */
506*49757Smarc /*  Returns:        0 for success, else nonzero error code         */
507*49757Smarc /*  Called by:      kernel software software,  this routine is in  */
508*49757Smarc /*                  the cdevsw table                               */
509*49757Smarc /*                                                                 */
510*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
511*49757Smarc 
512*49757Smarc xxwrite(dev, uio)
513*49757Smarc dev_t           dev;
514*49757Smarc struct uio     *uio;
515*49757Smarc {
516*49757Smarc     register struct tty *tp;
517*49757Smarc     if (dda_softc[UNIT(dev)].dda_state != S_LINK_UP)
518*49757Smarc 	return (ENXIO);
519*49757Smarc     tp = &xx_tty[LINE(dev)];
520*49757Smarc     return (*linesw[tp->t_line].l_write)(tp, uio);
521*49757Smarc }
522*49757Smarc 
523*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
524*49757Smarc /*%%                       XXIOCTL()                             %%*/
525*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
526*49757Smarc /*                                                                 */
527*49757Smarc /*  Purpose:                                                       */
528*49757Smarc /*                                                                 */
529*49757Smarc /*  Process ioctl request.                                         */
530*49757Smarc /*                                                                 */
531*49757Smarc /*  Call:           xxioctl(dev, cmd, data, flag)                  */
532*49757Smarc /*  Argument:       dev:   device                                  */
533*49757Smarc /*                  cmd:   ioctl command                           */
534*49757Smarc /*                  data:  pointer to data                         */
535*49757Smarc /*                  flag:  ignored                                 */
536*49757Smarc /*  Returns:        0 for sucess, else nonzero error code          */
537*49757Smarc /*  Called by:      kernel software software,  this routine is in  */
538*49757Smarc /*                  the cdevsw table                               */
539*49757Smarc /*                                                                 */
540*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
541*49757Smarc 
542*49757Smarc #define TIOACCQBIT (int)(0x80800000|('t'<<8)|125)
543*49757Smarc 
544*49757Smarc xxioctl(dev, cmd, data, flag)
545*49757Smarc dev_t           dev;
546*49757Smarc caddr_t         data;
547*49757Smarc {
548*49757Smarc     register struct tty *tp;
549*49757Smarc     int             error;
550*49757Smarc     tp = &xx_tty[LINE(dev)];
551*49757Smarc     if (cmd == TIOACCQBIT) {
552*49757Smarc #ifdef	DDADEBUG
553*49757Smarc 	if (DDADBCH(98, UNIT(dev))) {
554*49757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) ioctl qbit msg: cmd=%x ACC=%x\n",
555*49757Smarc 				  UNIT(dev), cmd, TIOACCQBIT
556*49757Smarc 		DDAELOG;
557*49757Smarc 	}
558*49757Smarc #endif  DDADEBUG
559*49757Smarc 	xx_qbit_msg(tp, UNIT(dev), data);
560*49757Smarc 	return (0);
561*49757Smarc     }
562*49757Smarc     error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag);
563*49757Smarc     if (error >= 0)
564*49757Smarc 	return (error);
565*49757Smarc     error = ttioctl(tp, cmd, data, flag);
566*49757Smarc     if (error >= 0) {
567*49757Smarc 	if (cmd == TIOCSETP || cmd == TIOCSETN)
568*49757Smarc 	    xxparam(dev);
569*49757Smarc 	return (error);
570*49757Smarc     }
571*49757Smarc     switch (cmd) {
572*49757Smarc     case TIOCREMOTE:
573*49757Smarc 	if (xxmode[LINE(dev)] == 0)
574*49757Smarc 	    return (EBUSY);
575*49757Smarc 	xxcntl(tp, XX_C_PAD, UNIT(dev));
576*49757Smarc 	break;
577*49757Smarc     case TIOCSBRK:
578*49757Smarc 	xxcntl(tp, XX_C_BREAK, UNIT(dev));
579*49757Smarc 	break;
580*49757Smarc     case TIOCCBRK:
581*49757Smarc     case TIOCSDTR:
582*49757Smarc     case TIOCCDTR:
583*49757Smarc 	break;
584*49757Smarc     default:
585*49757Smarc 	return (ENOTTY);
586*49757Smarc     }
587*49757Smarc     return (0);
588*49757Smarc }
589*49757Smarc 
590*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
591*49757Smarc /*%%                        XXPARAM()                            %%*/
592*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
593*49757Smarc /*                                                                 */
594*49757Smarc /*  Purpose:                                                       */
595*49757Smarc /*                                                                 */
596*49757Smarc /*  Set parameters from open or stty.                              */
597*49757Smarc /*  This routine is being left in as a dummy in case in the future */
598*49757Smarc /*  there is a mechanism for the host to send information i.e.     */
599*49757Smarc /*  "hangup line" to the ACP _XX                                   */
600*49757Smarc /*                                                                 */
601*49757Smarc /*  Call:           xxparam(dev)                                   */
602*49757Smarc /*  Argument:       dev:   device                                  */
603*49757Smarc /*  Returns:        none                                           */
604*49757Smarc /*  Called by:      none                                           */
605*49757Smarc /*                                                                 */
606*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
607*49757Smarc /*ARGSUSED*/
608*49757Smarc xxparam(dev)
609*49757Smarc dev_t           dev;
610*49757Smarc {
611*49757Smarc }
612*49757Smarc 
613*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
614*49757Smarc /*%%                        XXSTART()                            %%*/
615*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
616*49757Smarc /*                                                                 */
617*49757Smarc /*  Purpose:                                                       */
618*49757Smarc /*                                                                 */
619*49757Smarc /*  Start (restart) transmission on a given line.  This is the     */
620*49757Smarc /*  start routine which is called from above by the tty driver and */
621*49757Smarc /*  from below on a transmission complete interrupt for a given    */
622*49757Smarc /*  line.                                                          */
623*49757Smarc /*                                                                 */
624*49757Smarc /*  Call:           xxstart(tp)                                    */
625*49757Smarc /*  Argument:       tp:   pointer to tty structure                 */
626*49757Smarc /*  Returns:        none                                           */
627*49757Smarc /*  Called by:      tty driver                                     */
628*49757Smarc /*                  xxreset()                                      */
629*49757Smarc /*                                                                 */
630*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
631*49757Smarc 
632*49757Smarc xxstart(tp)
633*49757Smarc register struct tty *tp;
634*49757Smarc {
635*49757Smarc     register struct dda_softc *ds;
636*49757Smarc     register int    nch,
637*49757Smarc                     cc,
638*49757Smarc 		    k;
639*49757Smarc     register struct dda_cb *dc;
640*49757Smarc     register char  *cp,
641*49757Smarc                    *p;
642*49757Smarc     struct ifqueue *oq;
643*49757Smarc     struct mbuf    *m;
644*49757Smarc     padinfo	   *pp;
645*49757Smarc     int             unit,
646*49757Smarc                     line,
647*49757Smarc                     s,
648*49757Smarc 		    j;
649*49757Smarc     extern int      ttrstrt();
650*49757Smarc 
651*49757Smarc     line = tp - xx_tty;
652*49757Smarc     unit = UNIT(line);
653*49757Smarc     dc = (struct dda_cb *) tp->t_addr;
654*49757Smarc     ds = &dda_softc[unit];
655*49757Smarc     pp = &xx_padinfo[line];
656*49757Smarc 
657*49757Smarc     s = splimp();
658*49757Smarc 
659*49757Smarc #ifdef	DDADEBUG
660*49757Smarc     if (DDADBCH(99, unit)) {
661*49757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) xxstart: line %d t_state = %x\n",
662*49757Smarc 			  unit, line, tp->t_state
663*49757Smarc 	DDAELOG;
664*49757Smarc     }
665*49757Smarc #endif  DDADEBUG
666*49757Smarc 
667*49757Smarc     /* If it's currently active, or delaying, no need to do anything. */
668*49757Smarc     if ((tp->t_state & TS_CARR_ON) == 0) {
669*49757Smarc 	tp->t_state &= ~(TS_TTSTOP | TS_BUSY);
670*49757Smarc 	ttyflush(tp, FREAD | FWRITE);
671*49757Smarc 	tp->t_state &= ~TS_ASLEEP;
672*49757Smarc 	wakeup((caddr_t) &tp->t_outq);
673*49757Smarc 	goto out;
674*49757Smarc     }
675*49757Smarc     if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
676*49757Smarc 	goto out;
677*49757Smarc 
678*49757Smarc     /* wait for free */
679*49757Smarc     if (dda_softc[unit].dda_state != S_LINK_UP) {
680*49757Smarc 	ttyflush(tp, FREAD | FWRITE);
681*49757Smarc         DMESG(unit, 96, (DDALOG(LOG_ERR)
682*49757Smarc 			"dda%d:(x29) xxstart: unit offline\n", unit DDAELOG) );
683*49757Smarc 	goto out;
684*49757Smarc     }
685*49757Smarc     /* If the writer was sleeping on output overflow, wake him when low tide
686*49757Smarc      * is reached. */
687*49757Smarc     if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
688*49757Smarc 	if (tp->t_state & TS_ASLEEP) {
689*49757Smarc 	    tp->t_state &= ~TS_ASLEEP;
690*49757Smarc 	    wakeup((caddr_t) &tp->t_outq);
691*49757Smarc 	}
692*49757Smarc 	if (tp->t_wsel) {
693*49757Smarc 	    selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
694*49757Smarc 	    tp->t_wsel = 0;
695*49757Smarc 	    tp->t_state &= ~TS_WCOLL;
696*49757Smarc 	}
697*49757Smarc     }
698*49757Smarc     /* restart transmission unless output queue is empty */
699*49757Smarc     if (tp->t_outq.c_cc == 0)
700*49757Smarc 	goto out;
701*49757Smarc 
702*49757Smarc     /* if this is an outbound pad line and it's in command mode */
703*49757Smarc     if (pp->p_state == PS_COM) {
704*49757Smarc 	xxpadhandle(ds, tp, pp);
705*49757Smarc 	goto out;
706*49757Smarc     }
707*49757Smarc 
708*49757Smarc     /* Allocate an mbuf to stuff the chars into */
709*49757Smarc     m = 0;
710*49757Smarc     MGET(m, M_DONTWAIT, MT_DATA);
711*49757Smarc     if (m == 0) {
712*49757Smarc         DMESG(unit, 97, (DDALOG(LOG_ERR)
713*49757Smarc 			"dda%d:(x29) xxstart: could not get mbuf\n",
714*49757Smarc 			unit DDAELOG) );
715*49757Smarc 	goto out;
716*49757Smarc     }
717*49757Smarc     cp = mtod(m, char *);
718*49757Smarc     cc = 0;
719*49757Smarc 
720*49757Smarc     /* copy at most MLEN-1 chars out -- must save one byte for subfunc */
721*49757Smarc     while ((cc < MLEN - 1) && (tp->t_outq.c_cc > 0)) {
722*49757Smarc 	if (tp->t_flags & (RAW | LITOUT))
723*49757Smarc 	    nch = ndqb(&tp->t_outq, 0);
724*49757Smarc 	else {
725*49757Smarc 	    nch = ndqb(&tp->t_outq, 0200);
726*49757Smarc 	    if (nch == 0) {	/* if first item was a delay */
727*49757Smarc 		(void) getc(&tp->t_outq);	/* discard the character */
728*49757Smarc 		continue;
729*49757Smarc 	    }
730*49757Smarc 	}
731*49757Smarc 	if (nch > (MLEN - 1) - cc)
732*49757Smarc 	    nch = (MLEN - 1) - cc;
733*49757Smarc 
734*49757Smarc 	/* If any characters were set up, start transmission; */
735*49757Smarc 	if (nch) {
736*49757Smarc 	    j = q_to_b(&tp->t_outq, cp, nch);
737*49757Smarc 
738*49757Smarc #if OUTPUT_PARITY_MASK != 0377
739*49757Smarc 	    /* strip all characters as desired */
740*49757Smarc 	    for (p = cp, k = j; k; k--, p++)
741*49757Smarc 		*p &= OUTPUT_PARITY_MASK;
742*49757Smarc #endif
743*49757Smarc 
744*49757Smarc #ifdef	DDADEBUG
745*49757Smarc 	    if (DDADBCH(100, unit) && j != nch) {
746*49757Smarc 		DDALOG(LOG_DEBUG)
747*49757Smarc 		    "dda%d:(x29) xxstart: asked for %d got %d chars\n",
748*49757Smarc 		    unit, nch, j
749*49757Smarc 		DDAELOG;
750*49757Smarc 	    }
751*49757Smarc #endif  DDADEBUG
752*49757Smarc 
753*49757Smarc 	    cc += nch;
754*49757Smarc 	    cp += nch;
755*49757Smarc 	} else
756*49757Smarc 	    break;
757*49757Smarc     }
758*49757Smarc 
759*49757Smarc #ifdef	DDADEBUG
760*49757Smarc     if (DDADBCH(101, unit)) {
761*49757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) xxstart: mbuf %x len %d\n",
762*49757Smarc 			  unit, m, m->m_len
763*49757Smarc 	DDAELOG;
764*49757Smarc     }
765*49757Smarc #endif
766*49757Smarc 
767*49757Smarc     /* if any data was stuffed into the mbuf then send it */
768*49757Smarc     if (cc) {
769*49757Smarc 	m->m_dat[MLEN - 1] = 0;	/* subfunction: no Q-bit */
770*49757Smarc 	m->m_len = cc;
771*49757Smarc 	oq = &(dc->dc_oq);	/* point to output queue */
772*49757Smarc 	if (IF_QFULL(oq)) {	/* if q full */
773*49757Smarc 	    IF_DROP(oq);	/* drop the data */
774*49757Smarc 	    m_freem(m);
775*49757Smarc 	    ds->dda_if.if_collisions++;	/* for netstat display */
776*49757Smarc 	    splx(s);
777*49757Smarc 	    return (ENOBUFS);
778*49757Smarc 	}
779*49757Smarc 	IF_ENQUEUE(oq, m);	/* otherwise queue it */
780*49757Smarc 	tp->t_state |= TS_BUSY;
781*49757Smarc 	dda_start(ds, dc);	/* and try to output */
782*49757Smarc     } else
783*49757Smarc 	m_freem(m);
784*49757Smarc 
785*49757Smarc out:
786*49757Smarc     if (dc->dc_lcn != 0)	/* something left in oq? */
787*49757Smarc 	dda_start(ds, dc);	/* restart output */
788*49757Smarc     splx(s);
789*49757Smarc     return (0);
790*49757Smarc }
791*49757Smarc 
792*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
793*49757Smarc /*%%                        XXRESET()                            %%*/
794*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
795*49757Smarc /*                                                                 */
796*49757Smarc /*  Purpose:                                                       */
797*49757Smarc /*                                                                 */
798*49757Smarc /*  In response to UNIBUS reset, reset state and restart           */
799*49757Smarc /*  transmitters.                                                  */
800*49757Smarc /*                                                                 */
801*49757Smarc /*  Call:           xxreset(uban)                                  */
802*49757Smarc /*  Argument:       uban:  UNIBUS adaptor number                   */
803*49757Smarc /*  Returns:        none                                           */
804*49757Smarc /*  Called by:      kernel software in response to UNIBUS reset    */
805*49757Smarc /*                                                                 */
806*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
807*49757Smarc /*ARGSUSED*/
808*49757Smarc xxreset(uban)
809*49757Smarc int uban;
810*49757Smarc {
811*49757Smarc }
812*49757Smarc 
813*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
814*49757Smarc /*%%                        XXSTOP()                             %%*/
815*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
816*49757Smarc /*                                                                 */
817*49757Smarc /*  Purpose:                                                       */
818*49757Smarc /*                                                                 */
819*49757Smarc /*  Dummy stop routine.                                            */
820*49757Smarc /*                                                                 */
821*49757Smarc /*  Call:           xxstop(tp, flag)                               */
822*49757Smarc /*  Argument:       tp:    pointer to tty structure                */
823*49757Smarc /*                  flag:  indicates                               */
824*49757Smarc /*  Returns:        none                                           */
825*49757Smarc /*  Called by:      none                                           */
826*49757Smarc /*                                                                 */
827*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
828*49757Smarc /*ARGSUSED*/
829*49757Smarc xxstop(tp, flag)
830*49757Smarc struct tty     *tp;
831*49757Smarc int             flag;
832*49757Smarc {
833*49757Smarc }
834*49757Smarc 
835*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
836*49757Smarc /*%%                        XXSELECT()                           %%*/
837*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
838*49757Smarc /*                                                                 */
839*49757Smarc /*  Purpose:                                                       */
840*49757Smarc /*                                                                 */
841*49757Smarc /*  Circumvent bug in our bastardized design which causes ttselect */
842*49757Smarc /*  to fail.							   */
843*49757Smarc /*                                                                 */
844*49757Smarc /*  Call:           xxselect(dev, rw)                              */
845*49757Smarc /*  Argument:       dev:   device                                  */
846*49757Smarc /*                  rw:    read or write indicator                 */
847*49757Smarc /*  Returns:        0 or 1                                         */
848*49757Smarc /*  Called by:      none                                           */
849*49757Smarc /*                                                                 */
850*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
851*49757Smarc 
852*49757Smarc xxselect(dev, rw)
853*49757Smarc dev_t           dev;
854*49757Smarc int             rw;
855*49757Smarc {
856*49757Smarc #ifdef	DDADEBUG
857*49757Smarc     int unit = UNIT(dev);
858*49757Smarc     if (DDADBCH(102, unit))
859*49757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) select()\n", unit DDAELOG;
860*49757Smarc #endif  DDADEBUG
861*49757Smarc 
862*49757Smarc     return (ttselect(MAJLINE(dev), rw));
863*49757Smarc }
864*49757Smarc 
865*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
866*49757Smarc /*%%                                                             %%*/
867*49757Smarc /*%%                   LOCAL  FUNCTIONS                          %%*/
868*49757Smarc /*%%                                                             %%*/
869*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
870*49757Smarc 
871*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
872*49757Smarc /*%%                      X29_SUPR()                             %%*/
873*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
874*49757Smarc /*                                                                 */
875*49757Smarc /*  Purpose:                                                       */
876*49757Smarc /*                                                                 */
877*49757Smarc /*       This routine processes received supervisor messages.      */
878*49757Smarc /*       Depending on the message type, the appropriate action is  */
879*49757Smarc /*       taken.                                                    */
880*49757Smarc /*                                                                 */
881*49757Smarc /*  Call:              x29_supr(ds, p)                             */
882*49757Smarc /*  Arguments:         ds:  pointer to dev control block struct    */
883*49757Smarc /*                     p:   pointer to a character array           */
884*49757Smarc /*                              containing the supervisor message  */
885*49757Smarc /*  Returns:           nothing                                     */
886*49757Smarc /*  Called by:         dda_supr()                                  */
887*49757Smarc /*                                                                 */
888*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
889*49757Smarc 
890*49757Smarc PRIVATE void
891*49757Smarc x29_supr(ds, p)
892*49757Smarc struct dda_softc *ds;
893*49757Smarc u_char          p[];
894*49757Smarc {
895*49757Smarc     register struct dda_cb *dc;
896*49757Smarc     register struct tty *tp;
897*49757Smarc     register int    lcn;
898*49757Smarc     int   	    maxlcn;
899*49757Smarc     int		    line;
900*49757Smarc 
901*49757Smarc #ifdef DDADEBUG
902*49757Smarc     if (DDADBCH(103, ds->dda_if.if_unit)) {
903*49757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) x29_supr()\n", ds->dda_if.if_unit
904*49757Smarc 	DDAELOG;
905*49757Smarc     }
906*49757Smarc #endif  DDADEBUG
907*49757Smarc 
908*49757Smarc     switch (p[0]) {
909*49757Smarc     case LINE_STATUS:		/* link status msg */
910*49757Smarc     case RESTART:		/* restart received */
911*49757Smarc     case RSTRT_ACK:		/* restart ack */
912*49757Smarc     case STATRESP:		/* Statistics Response from FEP */
913*49757Smarc 	DMESG(ds->dda_if.if_unit, 98, (DDALOG(LOG_ERR)
914*49757Smarc 		"dda%d:(x29) x29_supr: unexpected message type\n",
915*49757Smarc 		ds->dda_if.if_unit DDAELOG));
916*49757Smarc 	break;
917*49757Smarc     case ANSWER:		/* call answered */
918*49757Smarc 	lcn = p[1] / 2;
919*49757Smarc 	dc = &(ds->dda_cb[lcn]);
920*49757Smarc 	if (dc->dc_state == LC_CALL_PENDING) {	/* if a call pending */
921*49757Smarc 	    decode_answer(p, dc);
922*49757Smarc 	    dc->dc_state = LC_DATA_IDLE;	/* set state */
923*49757Smarc 	    dc->dc_flags = DC_X29;
924*49757Smarc 	    line = dc->dc_line;			/* which line are we? */
925*49757Smarc #ifdef DDADEBUG
926*49757Smarc 	    if (DDADBCH(114, ds->dda_if.if_unit)) {
927*49757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) x29_supr: answer: line=%d\n",
928*49757Smarc 			ds->dda_if.if_unit, line
929*49757Smarc 		DDAELOG;
930*49757Smarc 	    }
931*49757Smarc #endif  DDADEBUG
932*49757Smarc 
933*49757Smarc 	    if (line == -1) {				/* fubar! */
934*49757Smarc 		DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
935*49757Smarc 		    "dda%d:(x29) x29_supr: answer: line was -1, VC 0x%x\n",
936*49757Smarc 		    ds->dda_if.if_unit, p[1] DDAELOG));
937*49757Smarc 	    }
938*49757Smarc 
939*49757Smarc 	    xx_padinfo[line].p_state = PS_PAD;
940*49757Smarc 	    xxstart(&xx_tty[line]);
941*49757Smarc 	} else {
942*49757Smarc 	    DMESG(ds->dda_if.if_unit, 108, (DDALOG(LOG_ERR)
943*49757Smarc 		"dda%d:(x29) x29_supr: unexpected answer on LCN %d\n",
944*49757Smarc 		ds->dda_if.if_unit, lcn DDAELOG));
945*49757Smarc 	}
946*49757Smarc 	if (LOG_CALLS) {
947*49757Smarc 	    DDALOG(LOG_INFO) "dda%d:(x29) LCN %d: connected\n",
948*49757Smarc 			     ds->dda_if.if_unit, lcn
949*49757Smarc 	    DDAELOG;
950*49757Smarc 	}
951*49757Smarc 	break;
952*49757Smarc 
953*49757Smarc     case RING:			/* incoming call */
954*49757Smarc 	if (decode_ring(p)) {
955*49757Smarc 	    /* find a free lcn associated with a XX_HOST open */
956*49757Smarc 	    dc = &ds->dda_cb[1];
957*49757Smarc 	    maxlcn = nddach[ds->dda_if.if_unit];
958*49757Smarc 	    for (lcn = 1; lcn <= maxlcn; lcn++) {
959*49757Smarc 		if (dc->dc_state == LC_IDLE && dc->dc_flags & DC_X29W)
960*49757Smarc 		    break;
961*49757Smarc 		dc++;
962*49757Smarc 	    }
963*49757Smarc 	    if (lcn > maxlcn) {				/* if no free lcn's */
964*49757Smarc 		if (LOG_BUSY) {
965*49757Smarc 		    DDALOG(LOG_ERR)
966*49757Smarc 			"dda%d:(x29) no free X29W lcns, call rejected, vc=0x%x\n",
967*49757Smarc 			ds->dda_if.if_unit, p[1]
968*49757Smarc 		    DDAELOG;
969*49757Smarc 		}
970*49757Smarc 		send_supr(ds, CLEARVC, p[2], 0);	/* clear call */
971*49757Smarc 		break;					/* exit case */
972*49757Smarc 	    }
973*49757Smarc 
974*49757Smarc 	    /* got a good lcn, now use it */
975*49757Smarc 
976*49757Smarc #ifdef DDADEBUG
977*49757Smarc 	    if (DDADBCH(103, ds->dda_if.if_unit)) {
978*49757Smarc 		DDALOG(LOG_ERR) "dda%d:(x29) supr_msg: call from 0x%0x\n",
979*49757Smarc 		       ds->dda_if.if_unit, (u_long) dc->dc_inaddr.s_addr
980*49757Smarc 		DDAELOG;
981*49757Smarc 	    }
982*49757Smarc #endif DDADEBUG
983*49757Smarc 
984*49757Smarc 	    dc->dc_state = LC_DATA_IDLE;	/* set state */
985*49757Smarc 	    dc->dc_pktsizein = 0;
986*49757Smarc 	    dc->dc_pktsizeout = 0;
987*49757Smarc 	    dc->dc_wsizein = 0;
988*49757Smarc 	    dc->dc_wsizeout = 0;
989*49757Smarc 	    dc->dc_flags = DC_X29;
990*49757Smarc 	    send_supr(ds, ANSWER, lcn * 2, p[2]);	/* send answer */
991*49757Smarc 	    if (LOG_CALLS) {
992*49757Smarc 		DDALOG(LOG_INFO) "dda%d:(x29) Call accepted LCN %d\n",
993*49757Smarc 	  		         ds->dda_if.if_unit, dc->dc_lcn
994*49757Smarc 		DDAELOG;
995*49757Smarc 	    }
996*49757Smarc 
997*49757Smarc 	    line = dc->dc_line;
998*49757Smarc 
999*49757Smarc #ifdef DDADEBUG
1000*49757Smarc 	    if (DDADBCH(114, ds->dda_if.if_unit)) {
1001*49757Smarc 		DDALOG(LOG_DEBUG) "dda%d:(x29) x29_supr: ring: line=%d\n",
1002*49757Smarc 			ds->dda_if.if_unit, line
1003*49757Smarc 		DDAELOG;
1004*49757Smarc 	    }
1005*49757Smarc #endif  DDADEBUG
1006*49757Smarc 
1007*49757Smarc 	    if (line == -1) {				/* fubar! */
1008*49757Smarc 		DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
1009*49757Smarc 		    "dda%d:(x29) x29_supr: ring: line was -1, VC 0x%x\n",
1010*49757Smarc 		    ds->dda_if.if_unit, p[1] DDAELOG));
1011*49757Smarc 		break;
1012*49757Smarc 	    }
1013*49757Smarc 
1014*49757Smarc 	    tp = &xx_tty[line];
1015*49757Smarc 	    xx_padinfo[line].p_state = PS_XFR;
1016*49757Smarc 	    wakeup((caddr_t) &tp->t_rawq);
1017*49757Smarc 	    tp->t_state |= TS_CARR_ON;
1018*49757Smarc #if ACC_ULTRIX > 00
1019*49757Smarc 	    tp->t_state &= ~TS_ONDELAY;
1020*49757Smarc #endif
1021*49757Smarc 	    /* I would prefer to wait a bit before sending this */
1022*49757Smarc 	    send_x29_param_msg(ds, dc, SET_PAD,
1023*49757Smarc 			       x29_callin_setparams,
1024*49757Smarc 			       sizeof(x29_callin_setparams));
1025*49757Smarc 	} else {		/* bad decode */
1026*49757Smarc 	    send_supr(ds, CLEARVC, p[2], 0);	/* clear call */
1027*49757Smarc 	    DMESG(ds->dda_if.if_unit, 100, (DDALOG(LOG_ERR)
1028*49757Smarc 		"dda%d:(x29) Bad decode, call REJECTED VC 0x%x\n",
1029*49757Smarc 		ds->dda_if.if_unit, p[1] DDAELOG));
1030*49757Smarc 	}
1031*49757Smarc 	break;
1032*49757Smarc 
1033*49757Smarc     case CLEARLC:		/* clear by LCN */
1034*49757Smarc 	lcn = p[1] / 2;		/* get LCN */
1035*49757Smarc 	dc = &(ds->dda_cb[lcn]);
1036*49757Smarc 	if (dc->dc_state != LC_CLR_PENDING) {	/* if no clear pending */
1037*49757Smarc 	    send_supr(ds, CLEARLC, p[1], 0);	/* ack the clear */
1038*49757Smarc 	}
1039*49757Smarc 	if (dc->dc_state == LC_CALL_PENDING)	/* call is cleared */
1040*49757Smarc 	    DMESG(ds->dda_if.if_unit, 101, (DDALOG(LOG_ERR)
1041*49757Smarc 	    	"dda%d:(x29) Call cleared LCN %d (%x %x)\n",
1042*49757Smarc 	        ds->dda_if.if_unit, dc->dc_lcn, p[2], p[4] DDAELOG));
1043*49757Smarc 
1044*49757Smarc 	hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_IDLE);
1045*49757Smarc 	dc->dc_state = LC_IDLE;
1046*49757Smarc 	dc->dc_timer = TMO_OFF;	/* stop timer */
1047*49757Smarc 	dc->dc_wsizein = dc->dc_wsizeout = 0;
1048*49757Smarc 	dc->dc_pktsizein = dc->dc_pktsizeout = 0;
1049*49757Smarc 	abort_io(ds->dda_if.if_unit, lcn);
1050*49757Smarc 	xx_tp_hangup(ds, dc);	/* will clear flags */
1051*49757Smarc 	break;
1052*49757Smarc 
1053*49757Smarc     case CLEARVC:		/* clear by VCN */
1054*49757Smarc 	send_supr(ds, CLEARVC, p[1], 0);	/* send clear ack */
1055*49757Smarc 	if (LOG_CALLS) {
1056*49757Smarc 	    DDALOG(LOG_INFO)
1057*49757Smarc 		"dda%d:(x29) Network cleared VC %x (%x %x)\n",
1058*49757Smarc 	        ds->dda_if.if_unit, p[1], p[2], p[4]
1059*49757Smarc 	    DDAELOG;
1060*49757Smarc 	}
1061*49757Smarc 	break;
1062*49757Smarc 
1063*49757Smarc     case RESET:		/* X25 reset */
1064*49757Smarc 	send_supr(ds, RESET_ACK, p[1], 0);	/* send reset ack */
1065*49757Smarc 	abort_io(ds->dda_if.if_unit, (int) p[1] / 2);
1066*49757Smarc 	DMESG(ds->dda_if.if_unit, 102, (DDALOG(LOG_ERR)
1067*49757Smarc 	    "dda%d:(x29) X25 RESET on LCN %d (%x %x)\n",
1068*49757Smarc 	    ds->dda_if.if_unit, p[1] / 2, p[2], p[4] DDAELOG));
1069*49757Smarc 	break;
1070*49757Smarc 
1071*49757Smarc     case INTERRUPT:		/* X25 interrupt */
1072*49757Smarc #ifdef INDICATE_BREAK_ON_INTERRUPT
1073*49757Smarc 	lcn  = p[1] / 2;
1074*49757Smarc 	dc   = &(ds->dda_cb[lcn]);
1075*49757Smarc 
1076*49757Smarc 	line = dc->dc_line;
1077*49757Smarc 
1078*49757Smarc 	if (line == -1) {				/* fubar! */
1079*49757Smarc 	    DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
1080*49757Smarc 		"dda%d:(x29) x29_supr: break: line was -1, VC 0x%x\n",
1081*49757Smarc 		ds->dda_if.if_unit, p[1] DDAELOG));
1082*49757Smarc 	    break;
1083*49757Smarc 	}
1084*49757Smarc 
1085*49757Smarc 	tp   = &xx_tty[line];
1086*49757Smarc 
1087*49757Smarc 	if (tp->t_flags & RAW)
1088*49757Smarc 	    c = 0;
1089*49757Smarc 	else
1090*49757Smarc #if ACC_ULTRIX >= 30
1091*49757Smarc 	    c = tp->c_cc[VINTR];/* else make it the interrupt */
1092*49757Smarc #else
1093*49757Smarc 	    c = tp->t_intrc;	/* else make it the interrupt */
1094*49757Smarc #endif
1095*49757Smarc #if NBK > 0
1096*49757Smarc 	if (tp->t_line == NETLDISC) {
1097*49757Smarc 	    BKINPUT(c, tp);
1098*49757Smarc 	} else
1099*49757Smarc #endif
1100*49757Smarc 	    (*linesw[tp->t_line].l_rint) (c, tp);
1101*49757Smarc 	/* send_supr (ds, INTR_ACK, p[1], 0); 	not needed -- done by FE */
1102*49757Smarc #endif
1103*49757Smarc 	break;
1104*49757Smarc 
1105*49757Smarc     case INTR_ACK:
1106*49757Smarc 	/* quietly drop the acknowledgement */
1107*49757Smarc 	break;
1108*49757Smarc     default:
1109*49757Smarc 	DMESG(ds->dda_if.if_unit, 104, (DDALOG(LOG_ERR)
1110*49757Smarc 	    "dda%d:(x29) supervisor error (%x %x %x %x)\n",
1111*49757Smarc 	    ds->dda_if.if_unit, p[0], p[1], p[2], p[3] DDAELOG));
1112*49757Smarc     }
1113*49757Smarc }
1114*49757Smarc 
1115*49757Smarc 	/* hangup any attached processes */
1116*49757Smarc PRIVATE void
1117*49757Smarc xx_tp_hangup(ds, dc)
1118*49757Smarc struct dda_softc *ds;
1119*49757Smarc register struct dda_cb *dc;
1120*49757Smarc {
1121*49757Smarc     register struct tty *tp;
1122*49757Smarc     register padinfo    *pp;
1123*49757Smarc     register int         line;
1124*49757Smarc 
1125*49757Smarc     line = dc->dc_line;
1126*49757Smarc 
1127*49757Smarc     if (line == -1) {				/* fubar! */
1128*49757Smarc 	DMESG(ds->dda_if.if_unit, 107, (DDALOG(LOG_ERR)
1129*49757Smarc 	    "dda%d:(x29) xx_tp_hangup: line was -1\n",
1130*49757Smarc 	    ds->dda_if.if_unit DDAELOG));
1131*49757Smarc 	return;
1132*49757Smarc     }
1133*49757Smarc 
1134*49757Smarc     tp   = &xx_tty[line];
1135*49757Smarc     pp   = &xx_padinfo[line];
1136*49757Smarc 
1137*49757Smarc     if (pp->p_flow != P_NOBLOCK) {	/* currently blocked? */
1138*49757Smarc 	register struct hdx_chan *hc;
1139*49757Smarc 	hc = (struct hdx_chan *) & dc->dc_rchan;
1140*49757Smarc 	dda_rrq(ds, hc);	/* make sure we hang a read */
1141*49757Smarc     }
1142*49757Smarc     pp->p_flow = P_NOBLOCK;
1143*49757Smarc     tp->t_state &= ~(TS_CARR_ON | TS_ASLEEP | TS_BUSY);
1144*49757Smarc     ttyflush(tp, FREAD | FWRITE);
1145*49757Smarc     gsignal(tp->t_pgrp, SIGHUP);
1146*49757Smarc     gsignal(tp->t_pgrp, SIGCONT);
1147*49757Smarc     tp->t_state &= ~TS_ASLEEP;
1148*49757Smarc     wakeup((caddr_t) &tp->t_outq);
1149*49757Smarc     xxmode[line] = MODE_UNUSED;
1150*49757Smarc     tp->t_addr = (caddr_t) NULL;
1151*49757Smarc     pp->p_state = PS_IDLE;
1152*49757Smarc     if (pp->p_mchsav) {
1153*49757Smarc 	m_freem(pp->p_mchsav);
1154*49757Smarc 	pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
1155*49757Smarc     }
1156*49757Smarc     dc->dc_flags &= ~(DC_X29 | DC_X29W);	/* release to others */
1157*49757Smarc }
1158*49757Smarc 
1159*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1160*49757Smarc /*%%                      X29_DATA()                             %%*/
1161*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1162*49757Smarc /*                                                                 */
1163*49757Smarc /*  Purpose:                                                       */
1164*49757Smarc /*                                                                 */
1165*49757Smarc /*    This routine is called when a data channel I/O completes.    */
1166*49757Smarc /*    If the completion was for a write, an attempt is made to     */
1167*49757Smarc /*    start output on the next packet waiting for output on that   */
1168*49757Smarc /*    LCN.  If the completion was for a read, the received packet  */
1169*49757Smarc /*    is sent to the IP input queue (if no error) and another read */
1170*49757Smarc /*    is started on the LCN.                                       */
1171*49757Smarc /*                                                                 */
1172*49757Smarc /*  Call:              x29_data(ds, hc, cc, cnt)                   */
1173*49757Smarc /*  Argument:          ds:  device control block                   */
1174*49757Smarc /*                     hc:  half duplex channel control block      */
1175*49757Smarc /*                     cc:   Mailbox I/O completion status         */
1176*49757Smarc /*                     cnt:  byte count                            */
1177*49757Smarc /*  Returns:           nothing                                     */
1178*49757Smarc /*  Called by:         ddainta()                                   */
1179*49757Smarc /*                                                                 */
1180*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1181*49757Smarc 
1182*49757Smarc #define QBIT	0x80
1183*49757Smarc 
1184*49757Smarc PRIVATE void
1185*49757Smarc x29_data(ds, hc, cc, cnt, subcc)
1186*49757Smarc register struct dda_softc *ds;
1187*49757Smarc register struct hdx_chan *hc;
1188*49757Smarc int             cc,
1189*49757Smarc                 cnt,
1190*49757Smarc                 subcc;
1191*49757Smarc {
1192*49757Smarc     register struct dda_cb *dc = &(ds->dda_cb[hc->hc_chan / 2]);
1193*49757Smarc     register struct tty *tp;
1194*49757Smarc 
1195*49757Smarc #ifdef DDADEBUG
1196*49757Smarc     if (DDADBCH(104, ds->dda_if.if_unit)) {
1197*49757Smarc  	DDALOG(LOG_DEBUG)
1198*49757Smarc 	    "dda%d:(x29) x29_data: chan=%x cc=%x cnt=%x subcc=%x\n",
1199*49757Smarc 	    ds->dda_if.if_unit, hc->hc_chan, cc, cnt, subcc
1200*49757Smarc 	DDAELOG;
1201*49757Smarc     }
1202*49757Smarc #endif DDADEBUG
1203*49757Smarc 
1204*49757Smarc     if (hc->hc_chan & 0x01) {	/* if write, fire up next output */
1205*49757Smarc #ifdef DDADEBUG
1206*49757Smarc 	dc->dc_out_t = TMO_OFF;	/* turn off output completion timer */
1207*49757Smarc #endif
1208*49757Smarc 
1209*49757Smarc 	if ((hc->hc_func != DDAABT) && (hc->hc_curr = hc->hc_curr->m_next))
1210*49757Smarc 	    dda_wrq(ds, hc, 0);
1211*49757Smarc 	else {
1212*49757Smarc 	    /* it is abort | no more data left */
1213*49757Smarc 	    char            qbit_indicator;
1214*49757Smarc 	    qbit_indicator = hc->hc_mbuf->m_dat[MLEN - 1];
1215*49757Smarc 	    m_freem(hc->hc_mbuf);
1216*49757Smarc 	    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
1217*49757Smarc 	    if (hc->hc_func == DDAABT) {
1218*49757Smarc 		hc->hc_func &= ~DDAABT;
1219*49757Smarc 		hc->hc_inv &= ~INVALID_MBUF;
1220*49757Smarc 	    } else
1221*49757Smarc 		ds->dda_if.if_opackets++;
1222*49757Smarc 	    dc->dc_flags &= ~DC_OBUSY;
1223*49757Smarc 
1224*49757Smarc 	    if (qbit_indicator == QBIT) {	/* Q-bit packet? */
1225*49757Smarc 		dda_start(ds, dc);		/* restart output */
1226*49757Smarc 	    } else {
1227*49757Smarc 		tp = &xx_tty[dc->dc_line];
1228*49757Smarc 		tp->t_state &= ~TS_BUSY;
1229*49757Smarc 		xxstart(tp);	/* restart tty output */
1230*49757Smarc 	    }
1231*49757Smarc 	}
1232*49757Smarc 
1233*49757Smarc 	/* it's a packet coming in from the front end to the host */
1234*49757Smarc     } else {
1235*49757Smarc #ifdef DDADEBUG
1236*49757Smarc 	dc->dc_flags &= ~DC_IPEND;
1237*49757Smarc #endif
1238*49757Smarc 	hc = &dc->dc_rchan;
1239*49757Smarc 
1240*49757Smarc #ifdef DDADEBUG
1241*49757Smarc 	if (DDADBCH(105, ds->dda_if.if_unit)) {
1242*49757Smarc 	    u_char         *p;
1243*49757Smarc 	    DDALOG(LOG_DEBUG) "dda%d:(x29) ", ds->dda_if.if_unit DDAELOG;
1244*49757Smarc 	    p = mtod(hc->hc_curr, u_char *);
1245*49757Smarc 	    prt_bytes(ds->dda_if.if_unit, "received data", p, (cnt < 64 ? cnt : 64));
1246*49757Smarc 	}
1247*49757Smarc 	if (DDADBCH(106, ds->dda_if.if_unit)) {
1248*49757Smarc 	    DDALOG(LOG_DEBUG)
1249*49757Smarc 		"dda%d:(x29) x29_data: read complete mbuf=%x curr=%x\n",
1250*49757Smarc 		ds->dda_if.if_unit, hc->hc_mbuf, hc->hc_curr
1251*49757Smarc 	    DDAELOG;
1252*49757Smarc 	}
1253*49757Smarc #endif DDADEBUG
1254*49757Smarc 
1255*49757Smarc 	if (dc->dc_state != LC_DATA_IDLE) {
1256*49757Smarc 	    m_freem(hc->hc_mbuf);	/* toss the packet, lcn is dead */
1257*49757Smarc 	    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
1258*49757Smarc 	} else if (cc == DDAIOCOK || (cc == DDAIOCOKP && !(subcc & QBIT))) {
1259*49757Smarc 	/* Queue up I/O completion OK transfers and I/O OK with more data
1260*49757Smarc 	 * pending transfers (as long as it's not a Qbit message).
1261*49757Smarc 	 * This algorythm operates differently than the IP handler due
1262*49757Smarc 	 * to the fact that we don't need to wait for the entire X.25
1263*49757Smarc 	 * packet to arrive on the host before we assemble it.  To do
1264*49757Smarc 	 * so should be OK,  but unfortunately it seems some brain-dead
1265*49757Smarc 	 * PAD's generate packets with the M-bit set if they have more
1266*49757Smarc 	 * data in their internal buffers.  This can cause the system
1267*49757Smarc 	 * to burn up mbufs waiting for us to finally receive a packet
1268*49757Smarc 	 * with the M-bit not set.  However, we should hold up on processing
1269*49757Smarc 	 * packets with both the Q-bit and the M-bit set until we receive
1270*49757Smarc 	 * the entire Q-bit message.  If we get 30k Q-bit packets, we will
1271*49757Smarc 	 * die, but that is obscenely absurd in the first place.
1272*49757Smarc 	 * (sigh)	-- pst 7-19-89
1273*49757Smarc 	 */
1274*49757Smarc 
1275*49757Smarc #ifdef DDADEBUG
1276*49757Smarc 	    if (DDADBCH(107, ds->dda_if.if_unit)) {
1277*49757Smarc 		DDALOG(LOG_DEBUG)
1278*49757Smarc 		    "dda%d:(x29) x29_data: chan=%x DDAIOCOK\n",
1279*49757Smarc 		    ds->dda_if.if_unit, hc->hc_chan
1280*49757Smarc 		DDAELOG;
1281*49757Smarc 	    }
1282*49757Smarc #endif DDADEBUG
1283*49757Smarc 	    hc->hc_curr->m_len += cnt;	/* update byte count */
1284*49757Smarc 
1285*49757Smarc 	    ds->dda_if.if_ipackets++;
1286*49757Smarc 	    /* HANDLE THE DATA HERE */
1287*49757Smarc 	    if (subcc & QBIT) {
1288*49757Smarc 		int             len;
1289*49757Smarc 		char           *mcp;
1290*49757Smarc 		mcp = mtod(hc->hc_curr, char *);
1291*49757Smarc 		len = hc->hc_curr->m_len;
1292*49757Smarc 
1293*49757Smarc #ifdef DDADEBUG
1294*49757Smarc 		if (DDADBCH(108, ds->dda_if.if_unit))
1295*49757Smarc 		    prt_bytes(ds->dda_if.if_unit,
1296*49757Smarc 			      "(x29) Qbit:", mcp, (len < 64 ? len : 64));
1297*49757Smarc #endif DDADEBUG
1298*49757Smarc 
1299*49757Smarc 		if (*mcp == BREAK_INDIC) {	/* Break indication? */
1300*49757Smarc 		    register struct tty *tp;
1301*49757Smarc 		    if (x29_break_reply_is_required(mcp, len)) {
1302*49757Smarc 			/* tell pad to stop discarding output */
1303*49757Smarc 			send_x29_param_msg(ds, dc, SET_PAD,
1304*49757Smarc 					   x29_break_ack_params, 2);
1305*49757Smarc 		    }
1306*49757Smarc 		    hc->hc_curr->m_len = 1;	/* change data to single byte */
1307*49757Smarc 		    tp = &xx_tty[dc->dc_line];
1308*49757Smarc 		    if (tp->t_flags & RAW)	/* if port is in raw mode, */
1309*49757Smarc 			*mcp = 0;	/* make the byte a null */
1310*49757Smarc 		    else
1311*49757Smarc #if ACC_ULTRIX >= 30
1312*49757Smarc 			*mcp = tp->t_cc[VINTR];	/* else make it the interrupt */
1313*49757Smarc #else
1314*49757Smarc 			*mcp = tp->t_intrc;	/* else make it the interrupt */
1315*49757Smarc #endif
1316*49757Smarc 		    x29_dhandle(ds, dc, 0);
1317*49757Smarc 		    return;
1318*49757Smarc 		} else if (*mcp & READ_PAD) {
1319*49757Smarc 		    if (len == 1)	/* just a message, no params? */
1320*49757Smarc 			send_x29_param_msg(ds, dc, PAR_INDICATION,
1321*49757Smarc 					   x29_callout_params,
1322*49757Smarc 					   sizeof(x29_callout_params));
1323*49757Smarc 		    else
1324*49757Smarc 			send_x29_param_msg(ds, dc, PAR_INDICATION, mcp + 1, len - 1);
1325*49757Smarc 		    m_freem(hc->hc_mbuf);
1326*49757Smarc 		    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
1327*49757Smarc 		} else {
1328*49757Smarc 		    m_freem(hc->hc_mbuf);
1329*49757Smarc 		    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
1330*49757Smarc 		}
1331*49757Smarc 	    } else {			/* not Qbit data, process normally */
1332*49757Smarc 		x29_dhandle(ds, dc, 0);
1333*49757Smarc 		return;
1334*49757Smarc 	    }
1335*49757Smarc 	} else if (cc == DDAIOCOKP) {	/* good completion, more data pending */
1336*49757Smarc 	    hc->hc_curr->m_len += cnt;
1337*49757Smarc 	} else {			/* toss packet */
1338*49757Smarc 	    m_freem(hc->hc_mbuf);
1339*49757Smarc 	    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
1340*49757Smarc 	}
1341*49757Smarc 	/* hang a new data read */
1342*49757Smarc #ifdef DDADEBUG
1343*49757Smarc 	dc->dc_flags |= DC_IPEND;
1344*49757Smarc #endif
1345*49757Smarc 	dda_rrq(ds, hc);
1346*49757Smarc     }
1347*49757Smarc }
1348*49757Smarc 
1349*49757Smarc /* this routine copies chars from the dc_rchan mbuf to the upper
1350*49757Smarc  * level software.  If all the characters are read then the mbuf is
1351*49757Smarc  * freed and a new read is hung on the channel.
1352*49757Smarc  *
1353*49757Smarc  * This routine is called from below by the int A handler and from above
1354*49757Smarc  * by the device read routine.
1355*49757Smarc  */
1356*49757Smarc 
1357*49757Smarc PRIVATE void
1358*49757Smarc x29_dhandle(ds, dc, restart)
1359*49757Smarc register struct dda_softc *ds;
1360*49757Smarc register struct dda_cb *dc;
1361*49757Smarc int             restart;
1362*49757Smarc {
1363*49757Smarc     register struct tty *tp;
1364*49757Smarc     register struct hdx_chan *hc;
1365*49757Smarc     register padinfo *pp;
1366*49757Smarc     u_char         *cp,
1367*49757Smarc                     c;
1368*49757Smarc     struct mbuf    *m2,
1369*49757Smarc                    *m;
1370*49757Smarc     int             s,
1371*49757Smarc                     line;
1372*49757Smarc     register int    j;
1373*49757Smarc     static int      recurse = 0;
1374*49757Smarc 
1375*49757Smarc     s = splimp();
1376*49757Smarc 
1377*49757Smarc     if (recurse) {	/* don't allow ourselves to be called recursively */
1378*49757Smarc 	splx(s);
1379*49757Smarc 	return;
1380*49757Smarc     } else
1381*49757Smarc 	recurse = 1;
1382*49757Smarc 
1383*49757Smarc     hc = (struct hdx_chan *) &dc->dc_rchan;
1384*49757Smarc 
1385*49757Smarc     line = dc->dc_line;
1386*49757Smarc 
1387*49757Smarc     tp = &xx_tty[line];
1388*49757Smarc     pp = &xx_padinfo[line];
1389*49757Smarc 
1390*49757Smarc     if (restart) {		/* trying to restart input? */
1391*49757Smarc 	j  = pp->p_flow;
1392*49757Smarc 	m  = pp->p_mchsav;
1393*49757Smarc 	m2 = pp->p_msav;
1394*49757Smarc 
1395*49757Smarc #ifdef DDADEBUG
1396*49757Smarc 	if (DDADBCH(109, ds->dda_if.if_unit)) {
1397*49757Smarc 	    DDALOG(LOG_DEBUG)
1398*49757Smarc 		"dda%d:(x29) flow restart [%d] in %x\n",
1399*49757Smarc 		ds->dda_if.if_unit, j, m
1400*49757Smarc 	    DDAELOG;
1401*49757Smarc 	}
1402*49757Smarc #endif DDADEBUG
1403*49757Smarc 
1404*49757Smarc     } else {
1405*49757Smarc 	j = P_NOBLOCK;
1406*49757Smarc 	m2 = m = hc->hc_mbuf;	/* que mbuf chain */
1407*49757Smarc     }
1408*49757Smarc 
1409*49757Smarc     if (m == 0) {
1410*49757Smarc 	DMESG(ds->dda_if.if_unit, 105, (DDALOG(LOG_ERR)
1411*49757Smarc 		"dda%d:(x29) x29_dhandle: null mbuf\n",
1412*49757Smarc 		ds->dda_if.if_unit DDAELOG));
1413*49757Smarc 	hc->hc_mbuf = hc->hc_curr = (struct mbuf *) NULL;
1414*49757Smarc 	dda_rrq(ds, hc);
1415*49757Smarc 	goto out;
1416*49757Smarc     }
1417*49757Smarc     while (m2) {
1418*49757Smarc 	cp = mtod(m2, u_char *);
1419*49757Smarc 	for (; j < m2->m_len; j++) {
1420*49757Smarc 	    c = cp[j] & INPUT_PARITY_MASK;
1421*49757Smarc 	    if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG - 2)
1422*49757Smarc 		if (!ttbreakc(c, tp))
1423*49757Smarc 		    continue;	/* dump the character */
1424*49757Smarc #if NBK > 0
1425*49757Smarc 	    if (tp->t_line == NETLDISC) {
1426*49757Smarc 		BKINPUT(c, tp);
1427*49757Smarc 	    } else
1428*49757Smarc #endif
1429*49757Smarc 		(*linesw[tp->t_line].l_rint) (c, tp);
1430*49757Smarc 
1431*49757Smarc 
1432*49757Smarc 	    /* Block further input iff: Current input > threshold AND input
1433*49757Smarc 	     * is available to user program */
1434*49757Smarc 
1435*49757Smarc 	    if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG / 4 &&
1436*49757Smarc 		((tp->t_flags & (RAW | CBREAK)) || (tp->t_canq.c_cc > 0))) {
1437*49757Smarc #ifdef DDADEBUG
1438*49757Smarc 		if (DDADBCH(109, ds->dda_if.if_unit)) {
1439*49757Smarc 		    DDALOG(LOG_DEBUG)
1440*49757Smarc 			"dda%d:(x29) flow on [%d] in %x of %d\n",
1441*49757Smarc 			ds->dda_if.if_unit, j, m2, m2->m_len
1442*49757Smarc 		    DDAELOG;
1443*49757Smarc 		}
1444*49757Smarc #endif DDADEBUG
1445*49757Smarc 		pp->p_flow = j + 1;
1446*49757Smarc 		pp->p_msav = m2;
1447*49757Smarc 		pp->p_mchsav = m;
1448*49757Smarc 		if (restart == 0)
1449*49757Smarc 		    hc->hc_mbuf = hc->hc_curr = (struct mbuf *) NULL;
1450*49757Smarc 		goto out;
1451*49757Smarc 	    }
1452*49757Smarc 	}
1453*49757Smarc 	m2 = m2->m_next;
1454*49757Smarc 	j = P_NOBLOCK;
1455*49757Smarc     }
1456*49757Smarc     if (restart)
1457*49757Smarc 	pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
1458*49757Smarc 
1459*49757Smarc     m_freem(m);
1460*49757Smarc     hc->hc_mbuf = hc->hc_curr = (struct mbuf *) NULL;
1461*49757Smarc     pp->p_flow  = P_NOBLOCK;
1462*49757Smarc 
1463*49757Smarc #ifdef DDADEBUG
1464*49757Smarc     dc->dc_flags |= DC_IPEND;
1465*49757Smarc #endif
1466*49757Smarc 
1467*49757Smarc     dda_rrq(ds, hc);
1468*49757Smarc 
1469*49757Smarc out:
1470*49757Smarc     recurse = 0;
1471*49757Smarc     splx(s);
1472*49757Smarc }
1473*49757Smarc 
1474*49757Smarc PRIVATE void
1475*49757Smarc xx_qbit_msg(tp, unit, msg)
1476*49757Smarc register struct tty *tp;
1477*49757Smarc int             unit;
1478*49757Smarc char           *msg;
1479*49757Smarc {
1480*49757Smarc     register struct dda_cb *dc;
1481*49757Smarc     register struct dda_softc *ds;
1482*49757Smarc     int             s;
1483*49757Smarc 
1484*49757Smarc     ds = &dda_softc[unit];
1485*49757Smarc     dc = (struct dda_cb *) tp->t_addr;
1486*49757Smarc     s = splimp();
1487*49757Smarc 
1488*49757Smarc #ifdef DDADEBUG
1489*49757Smarc     if (DDADBCH(110, unit)) {
1490*49757Smarc 	DDALOG(LOG_DEBUG)
1491*49757Smarc 	    "dda%d:(x29) xx_qbit_msg: %d %d %d\n",
1492*49757Smarc 	    unit, msg[0], msg[1], msg[2]
1493*49757Smarc 	DDAELOG;
1494*49757Smarc     }
1495*49757Smarc #endif DDADEBUG
1496*49757Smarc 
1497*49757Smarc     if (msg[1] < (MLEN - 4))
1498*49757Smarc 	send_x29_param_msg(ds, dc, msg[0], msg + 2, msg[1]);
1499*49757Smarc     splx(s);
1500*49757Smarc }
1501*49757Smarc 
1502*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1503*49757Smarc /*%%                        XXCNTL()                             %%*/
1504*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1505*49757Smarc /*                                                                 */
1506*49757Smarc /*  Purpose:                                                       */
1507*49757Smarc /*                                                                 */
1508*49757Smarc /*  Do modem control functions on a line.                          */
1509*49757Smarc /*                                                                 */
1510*49757Smarc /*  Call:           xxcntl(tp, c, d)                               */
1511*49757Smarc /*  Argument:       tp:   pointer to tty structure                 */
1512*49757Smarc /*                  c:    function code                            */
1513*49757Smarc /*                  unit: for unit number                          */
1514*49757Smarc /*  Returns:        none                                           */
1515*49757Smarc /*  Called by:      xxopen()                                       */
1516*49757Smarc /*                  xxclose()                                      */
1517*49757Smarc /*                  xxread()                                       */
1518*49757Smarc /*                  xxint()                                        */
1519*49757Smarc /*                                                                 */
1520*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1521*49757Smarc 
1522*49757Smarc PRIVATE void
1523*49757Smarc xxcntl(tp, c, unit)
1524*49757Smarc register struct tty *tp;
1525*49757Smarc int             c,
1526*49757Smarc                 unit;
1527*49757Smarc {
1528*49757Smarc     register struct dda_cb *dc;
1529*49757Smarc     register struct dda_softc *ds;
1530*49757Smarc     register padinfo *pp;
1531*49757Smarc     int             s,
1532*49757Smarc                     l;
1533*49757Smarc 
1534*49757Smarc     l = tp - xx_tty;
1535*49757Smarc     ds = &dda_softc[unit];
1536*49757Smarc     pp = &xx_padinfo[l];
1537*49757Smarc     s = splimp();
1538*49757Smarc 
1539*49757Smarc #ifdef DDADEBUG
1540*49757Smarc     if (DDADBCH(111, unit)) {
1541*49757Smarc 	DDALOG(LOG_DEBUG)
1542*49757Smarc 	    "dda%d:(x29) xxcntl: tp=0x%x line=%d\n", unit, tp, l
1543*49757Smarc 	DDAELOG;
1544*49757Smarc     }
1545*49757Smarc #endif DDADEBUG
1546*49757Smarc 
1547*49757Smarc     switch (c) {
1548*49757Smarc     case XX_C_PAD:
1549*49757Smarc 	if (tp->t_addr)
1550*49757Smarc 	    break;
1551*49757Smarc 	if (dc = find_free_lcn(ds)) { /* race against locate_x25_lcn */
1552*49757Smarc 	    dc->dc_flags = DC_X29;
1553*49757Smarc 	    dc->dc_line = l;
1554*49757Smarc 	    pp->p_state = PS_COM;
1555*49757Smarc 	    tp->t_addr = (caddr_t) dc;
1556*49757Smarc 	    tp->t_flags &= ~ECHO;
1557*49757Smarc 	    pp->p_flow = P_NOBLOCK;
1558*49757Smarc 	    pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
1559*49757Smarc 	    pp->p_idx = 0;
1560*49757Smarc 	    pp->p_line[0] = '\0';
1561*49757Smarc 	} else
1562*49757Smarc 	    tp->t_addr = (caddr_t) NULL;
1563*49757Smarc 	break;
1564*49757Smarc     case XX_C_HOST:
1565*49757Smarc 	if (tp->t_addr)
1566*49757Smarc 	    break;
1567*49757Smarc 	if (dc = find_free_lcn(ds)) { /* race against locate_x25_lcn */
1568*49757Smarc 	    dc->dc_flags = DC_X29W;
1569*49757Smarc 	    dc->dc_line = l;
1570*49757Smarc 	    pp->p_state = PS_WAIT;
1571*49757Smarc 	    pp->p_flow = P_NOBLOCK;
1572*49757Smarc 	    pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
1573*49757Smarc 	    tp->t_addr = (caddr_t) dc;
1574*49757Smarc 	} else
1575*49757Smarc 	    tp->t_addr = (caddr_t) NULL;
1576*49757Smarc 	break;
1577*49757Smarc     case XX_C_CLOSE:
1578*49757Smarc 	pp->p_state = PS_IDLE;
1579*49757Smarc 	if (pp->p_mchsav) {
1580*49757Smarc 	    m_freem(pp->p_mchsav);
1581*49757Smarc 	    pp->p_msav = pp->p_mchsav = (struct mbuf *) NULL;
1582*49757Smarc 	}
1583*49757Smarc 	dc = (struct dda_cb *) tp->t_addr;
1584*49757Smarc 	if (dc == 0)
1585*49757Smarc 	    break;
1586*49757Smarc 	if (pp->p_flow != P_NOBLOCK) {	/* currently blocked? */
1587*49757Smarc 	    register struct hdx_chan *hc;
1588*49757Smarc 	    hc = (struct hdx_chan *) &dc->dc_rchan;
1589*49757Smarc 	    dda_rrq(ds, hc);		/* make sure we hang a read */
1590*49757Smarc 	}
1591*49757Smarc #ifdef	DDADEBUG
1592*49757Smarc 	if (DDADBCH(111, unit)) {
1593*49757Smarc 	    static char *st[] = { "lcn down", "lcn restart", "idle",
1594*49757Smarc 				  "call pending", "data idle", "clear pending"
1595*49757Smarc 				};
1596*49757Smarc 	    DDALOG(LOG_DEBUG)
1597*49757Smarc 		"dda%d:(x29) xxcntl: close state: %s\n", unit, st[dc->dc_state]
1598*49757Smarc 	    DDAELOG;
1599*49757Smarc 	}
1600*49757Smarc #endif DDADEBUG
1601*49757Smarc 
1602*49757Smarc 	if (dc->dc_state == LC_DATA_IDLE || dc->dc_state == LC_CALL_PENDING)
1603*49757Smarc 	    clear_lcn(ds, dc);	/* send clear & set state to clr_pending */
1604*49757Smarc 				/* timers will convert it to LC_IDLE later */
1605*49757Smarc 
1606*49757Smarc #ifdef	DDADEBUG
1607*49757Smarc 	else
1608*49757Smarc 	    if (DDADBCH(111, unit)) {
1609*49757Smarc 		DDALOG(LOG_DEBUG)
1610*49757Smarc 		    "dda%d:(x29) xxcntl: warning: state not data_idle\n", unit
1611*49757Smarc 		DDAELOG;
1612*49757Smarc 	    }
1613*49757Smarc #endif
1614*49757Smarc 
1615*49757Smarc 	dc->dc_flags &= ~(DC_X29 | DC_X29W);	/* release to others */
1616*49757Smarc 	tp->t_addr = (caddr_t) NULL;
1617*49757Smarc 	break;
1618*49757Smarc     case XX_C_BREAK:
1619*49757Smarc 
1620*49757Smarc 	/* really should look at X.3 parameters to decide if an interrupt
1621*49757Smarc 	 * packet should be sent. instead, we take an action which assumes
1622*49757Smarc 	 * PAD parameter 7 has value 21 */
1623*49757Smarc 	dc = (struct dda_cb *) tp->t_addr;
1624*49757Smarc 	send_supr(ds, INTERRUPT, dc->dc_lcn * 2, 0);
1625*49757Smarc 	send_x29_param_msg(ds, dc, BREAK_INDIC, 0, 0);
1626*49757Smarc 	break;
1627*49757Smarc     }
1628*49757Smarc     splx(s);
1629*49757Smarc }
1630*49757Smarc 
1631*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1632*49757Smarc /*%%                     X29_INIT()                              %%*/
1633*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1634*49757Smarc /*                                                                 */
1635*49757Smarc /*  Purpose:                                                       */
1636*49757Smarc /*                                                                 */
1637*49757Smarc /*  Software reset, clear lines.                                   */
1638*49757Smarc /*                                                                 */
1639*49757Smarc /*  Call:           x29_init(unit, active);                        */
1640*49757Smarc /*  Argument:       unit:  ACP _XX device                          */
1641*49757Smarc /*  Returns:        none                                           */
1642*49757Smarc /*  Called by:      none                                           */
1643*49757Smarc /*                                                                 */
1644*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1645*49757Smarc 
1646*49757Smarc PRIVATE void
1647*49757Smarc x29_init(unit, active)
1648*49757Smarc int             unit,
1649*49757Smarc                 active;
1650*49757Smarc {
1651*49757Smarc     register int    i;
1652*49757Smarc     register padinfo *pp;
1653*49757Smarc 
1654*49757Smarc #ifdef	DDADEBUG
1655*49757Smarc     if (DDADBCH(113, unit)) {
1656*49757Smarc 	DDALOG(LOG_DEBUG) "dda%d:(x29) x29_init() active=%d\n",
1657*49757Smarc 			  unit, active
1658*49757Smarc 	DDAELOG;
1659*49757Smarc     }
1660*49757Smarc #endif  DDADEBUG
1661*49757Smarc 
1662*49757Smarc     if (active)
1663*49757Smarc 	xxclear(unit);
1664*49757Smarc     else {
1665*49757Smarc 	for (i = 0; i < XXLPERBRD; i++) {
1666*49757Smarc 	    xx_tty[unit * XXLPERBRD + i].t_state = PS_IDLE;
1667*49757Smarc 	    pp = &xx_padinfo[unit * XXLPERBRD + i];
1668*49757Smarc 	    pp->p_state = PS_IDLE;
1669*49757Smarc 	    pp->p_flow  = P_NOBLOCK;
1670*49757Smarc 	    pp->p_msav  = pp ->p_mchsav = (struct mbuf *) NULL;
1671*49757Smarc 	}
1672*49757Smarc     }
1673*49757Smarc }
1674*49757Smarc 
1675*49757Smarc PRIVATE void
1676*49757Smarc xxclear(unit)
1677*49757Smarc int             unit;
1678*49757Smarc {
1679*49757Smarc     register struct tty *tp;
1680*49757Smarc     register struct dda_softc *ds;
1681*49757Smarc     register struct dda_cb *dc;
1682*49757Smarc     int             i,
1683*49757Smarc                     state;
1684*49757Smarc 
1685*49757Smarc     ds = &dda_softc[unit];
1686*49757Smarc     for (i = 0, tp = &xx_tty[unit * XXLPERBRD]; i < XXLPERBRD; i++, tp++) {
1687*49757Smarc 	state = tp->t_state;
1688*49757Smarc #ifdef	DDADEBUG
1689*49757Smarc 	if (DDADBCH(112, unit) && state) {
1690*49757Smarc 	    DDALOG(LOG_DEBUG)
1691*49757Smarc 		"dda%d:(x29) xxclear: line=%d pgrp=%d state=%d\n",
1692*49757Smarc 		unit, i, tp->t_pgrp, state
1693*49757Smarc 	    DDAELOG;
1694*49757Smarc 	}
1695*49757Smarc #endif  DDADEBUG
1696*49757Smarc 	if (state & TS_WOPEN) {
1697*49757Smarc 	    tp->t_state &= ~TS_WOPEN;
1698*49757Smarc 	    wakeup(&tp->t_rawq);
1699*49757Smarc 	}
1700*49757Smarc 	if (tp->t_state) {
1701*49757Smarc 	    dc = (struct dda_cb *) tp->t_addr;
1702*49757Smarc 	    if (dc) {
1703*49757Smarc 		xx_tp_hangup(ds, dc);
1704*49757Smarc 		dc->dc_line = -1;	/* break correspondence */
1705*49757Smarc 	    }
1706*49757Smarc 	}
1707*49757Smarc     }
1708*49757Smarc }
1709*49757Smarc 
1710*49757Smarc /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1711*49757Smarc /*%%                        XXSHOW()                             %%*/
1712*49757Smarc /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1713*49757Smarc /*                                                                 */
1714*49757Smarc /*  Purpose:                                                       */
1715*49757Smarc /*                                                                 */
1716*49757Smarc /*      Show status of each active unit                            */
1717*49757Smarc /*                                                                 */
1718*49757Smarc /*  Call:           xxshow()                                       */
1719*49757Smarc /*  Argument:       none		                           */
1720*49757Smarc /*  Returns:        none                                           */
1721*49757Smarc /*  Called by:      none                                           */
1722*49757Smarc /*                                                                 */
1723*49757Smarc /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1724*49757Smarc 
1725*49757Smarc PRIVATE void
1726*49757Smarc xxshow()
1727*49757Smarc {
1728*49757Smarc     register struct tty *tp;
1729*49757Smarc     register padinfo    *pp;
1730*49757Smarc     int                  unit,
1731*49757Smarc                          i;
1732*49757Smarc     static char	        *st[] = { "idle", " com", " pad", "wait", "xfer" };
1733*49757Smarc 
1734*49757Smarc 
1735*49757Smarc     for (unit = 0; unit < (NDDA < XXBOARDS ? NDDA : XXBOARDS); unit++) {
1736*49757Smarc 	uprintf("\nACP5250/6250 X29 driver: state of unit %d -\n", unit);
1737*49757Smarc 	uprintf("line\tstate\tlcn\tflow\ttstate\ttflags\n");
1738*49757Smarc 
1739*49757Smarc 	for (i = 0, tp = &xx_tty[unit * XXLPERBRD]; i < XXLPERBRD; i++, tp++) {
1740*49757Smarc 	    if (tp->t_state) {
1741*49757Smarc 		pp = &xx_padinfo[i];
1742*49757Smarc 		uprintf("%d:\t%s\t%d\t%d\t%x\t%x\n", i, st[pp->p_state],
1743*49757Smarc 		       (struct dda_cb *) (tp->t_addr) - dda_softc[unit].dda_cb,
1744*49757Smarc 		       pp->p_flow, tp->t_state, tp->t_flags);
1745*49757Smarc 	    }
1746*49757Smarc 	}
1747*49757Smarc     }
1748*49757Smarc     uprintf("remaining lines free\n");
1749*49757Smarc }
1750*49757Smarc 
1751*49757Smarc /******************************************************************************
1752*49757Smarc  *                           PAD CODE
1753*49757Smarc  ******************************************************************************/
1754*49757Smarc /* PADCHARUP - Pass a character up towards the user */
1755*49757Smarc #define PADCHARUP(c,tp) (*linesw[(tp)->t_line].l_rint) ((c), (tp))
1756*49757Smarc 
1757*49757Smarc PRIVATE void
1758*49757Smarc xxpadhandle(ds, tp, pi)
1759*49757Smarc struct dda_softc *ds;
1760*49757Smarc struct tty     *tp;		/* pointer to relevant tty structure */
1761*49757Smarc padinfo        *pi;		/* pointer to relevant padinfo structure */
1762*49757Smarc {
1763*49757Smarc     register int    i;
1764*49757Smarc     register char   c;
1765*49757Smarc     register struct dda_cb *dc;
1766*49757Smarc     int             nch;
1767*49757Smarc     char            tbuf[CBSIZE];	/* CBSIZE is number of char in a
1768*49757Smarc 					 * cblock */
1769*49757Smarc     nch = q_to_b(&tp->t_outq, tbuf, CBSIZE);
1770*49757Smarc 
1771*49757Smarc     /* handle characters in command state. Its OK if were slow here because
1772*49757Smarc      * there is a person on the other end of the discussion */
1773*49757Smarc     dc = (struct dda_cb *) tp->t_addr;
1774*49757Smarc     for (i = 0; i < nch; i++) {
1775*49757Smarc 	if (pi->p_idx >= P_LINELEN) {
1776*49757Smarc 	    xxpadmsg("\r\ncommand too long\r\n@", tp);
1777*49757Smarc 	    pi->p_idx = 0;
1778*49757Smarc 	    return;
1779*49757Smarc 	}
1780*49757Smarc 	c = pi->p_line[pi->p_idx] = tbuf[i] & INPUT_PARITY_MASK;
1781*49757Smarc 	if (c == '\r' || c == '\n') {
1782*49757Smarc 	    PADCHARUP('\r', tp);
1783*49757Smarc 	    PADCHARUP('\n', tp);
1784*49757Smarc 	    pi->p_line[pi->p_idx] = '\0';
1785*49757Smarc 	    if (dc && dc->dc_state != LC_IDLE) {
1786*49757Smarc 		xxpadmsg("cannot call, line is in transition\r\n", tp);
1787*49757Smarc 		if (dc && dc->dc_state == LC_CALL_PENDING)
1788*49757Smarc 		    xxpadmsg("previous call still pending\r\n", tp);
1789*49757Smarc 	    } else if (xxpadparse(ds, pi, tp) == 0)
1790*49757Smarc 		PADCHARUP('@', tp);
1791*49757Smarc 	    pi->p_idx = 0;
1792*49757Smarc 	} else if (c == '\b' || c == '\177') {
1793*49757Smarc 	    if (pi->p_idx) {
1794*49757Smarc 		pi->p_idx--;
1795*49757Smarc 		xxpadmsg("\b \b", tp);
1796*49757Smarc 	    }
1797*49757Smarc 	} else {
1798*49757Smarc 	    pi->p_idx++;
1799*49757Smarc 	    PADCHARUP(c, tp);
1800*49757Smarc 	}
1801*49757Smarc     }
1802*49757Smarc }
1803*49757Smarc 
1804*49757Smarc PRIVATE int
1805*49757Smarc xxpadparse(ds, pi, tp)
1806*49757Smarc struct dda_softc *ds;
1807*49757Smarc padinfo        *pi;
1808*49757Smarc struct tty     *tp;
1809*49757Smarc {
1810*49757Smarc     char           *p = pi->p_line;
1811*49757Smarc 
1812*49757Smarc     if (*p == 'c' || *p == 'C') {	/* connect command */
1813*49757Smarc 	for (p++; *p == ' '; *p++);
1814*49757Smarc 	if (*p < '0' || *p > '9')
1815*49757Smarc 	    xxpadmsg("???\r\n", tp);
1816*49757Smarc 	else			/* place a call */
1817*49757Smarc 	    return xxpadcall(ds, p, tp);
1818*49757Smarc     } else if (*p)
1819*49757Smarc 	xxpadmsg("invalid command\r\n", tp);
1820*49757Smarc     return 0;
1821*49757Smarc }
1822*49757Smarc 
1823*49757Smarc PRIVATE int
1824*49757Smarc xxpadcall(ds, addr, tp)
1825*49757Smarc struct dda_softc *ds;
1826*49757Smarc char           *addr;
1827*49757Smarc struct tty     *tp;
1828*49757Smarc {
1829*49757Smarc     register int    i = 0;
1830*49757Smarc     struct in_addr  in;
1831*49757Smarc 
1832*49757Smarc     while (addr[i]) {
1833*49757Smarc 	if (addr[i] < '0' || addr[i] > '9') {
1834*49757Smarc 	    xxpadmsg("invalid address\r\n", tp);
1835*49757Smarc 	    return 0;
1836*49757Smarc 	}
1837*49757Smarc 	i++;
1838*49757Smarc     }
1839*49757Smarc     ddacb_called_addr[0] = i;
1840*49757Smarc     bcopy(addr, ddacb_called_addr + 1, i);
1841*49757Smarc     ddacb_user_data[0] = (u_char) 0;	/* no user data for now */
1842*49757Smarc     in.s_addr = 0;
1843*49757Smarc     return make_x25_call(ds, (struct dda_cb *) tp->t_addr, in, X25_PROTO_X29);
1844*49757Smarc }
1845*49757Smarc 
1846*49757Smarc PRIVATE void
1847*49757Smarc xxpadmsg(s, tp)
1848*49757Smarc char           *s;
1849*49757Smarc struct tty     *tp;
1850*49757Smarc {
1851*49757Smarc     while (*s) {
1852*49757Smarc 	PADCHARUP(*s, tp);
1853*49757Smarc 	s++;
1854*49757Smarc     }
1855*49757Smarc }
1856*49757Smarc 
1857*49757Smarc /*
1858*49757Smarc  * This routine is used to respond to
1859*49757Smarc  * READ_PARAMS and SET_READ_PARAMS requests, and also
1860*49757Smarc  * to send out a SET_PARAMS request for incoming calls.
1861*49757Smarc  * The outgoing pad supports NO parameters.
1862*49757Smarc  */
1863*49757Smarc send_x29_param_msg(ds, dc, type, msg, len)
1864*49757Smarc register struct dda_cb *dc;
1865*49757Smarc register struct dda_softc *ds;
1866*49757Smarc x29_pad_pair   *msg;
1867*49757Smarc {
1868*49757Smarc     struct mbuf    *m;
1869*49757Smarc     u_char         *p;
1870*49757Smarc     short           i;
1871*49757Smarc     register struct ifqueue *oq;
1872*49757Smarc     m = 0;			/* Allocate an mbuf to stuff the chars into */
1873*49757Smarc     MGET(m, M_DONTWAIT, MT_DATA);
1874*49757Smarc     if (m == 0) {
1875*49757Smarc 	DMESG(ds->dda_if.if_unit, 106, (DDALOG(LOG_ERR)
1876*49757Smarc 		"dda%d:(x29) couldn't get mbuf for QBIT message\n",
1877*49757Smarc 		ds->dda_if.if_unit DDAELOG));
1878*49757Smarc 	return;
1879*49757Smarc     }
1880*49757Smarc     m->m_dat[MLEN - 1] = QBIT;	/* set Q-bit */
1881*49757Smarc     p = mtod(m, u_char *);
1882*49757Smarc     len = len / 2;
1883*49757Smarc     *p++ = type;
1884*49757Smarc     if (type == PAR_INDICATION) {	/* our pad supports NO parameters */
1885*49757Smarc 	for (i = 0; i < len; i++) {
1886*49757Smarc 	    *p++ = msg[i].ref | 0x80;	/* set invalid bit */
1887*49757Smarc 	    *p++ = 1;		/* not implemented */
1888*49757Smarc 	}
1889*49757Smarc     } else {			/* BREAK_INDIC, SET_PAD to ack break */
1890*49757Smarc 	for (i = 0; i < len; i++) {
1891*49757Smarc 	    *p++ = msg[i].ref;
1892*49757Smarc 	    *p++ = msg[i].val;
1893*49757Smarc 	}
1894*49757Smarc     }
1895*49757Smarc     m->m_len = 1 + 2 * len;
1896*49757Smarc     oq = &(dc->dc_oq);		/* point to output queue */
1897*49757Smarc     if (IF_QFULL(oq)) {		/* if q full */
1898*49757Smarc 	IF_DROP(oq);		/* drop the data */
1899*49757Smarc 	m_freem(m);
1900*49757Smarc 	ds->dda_if.if_collisions++;	/* for netstat display */
1901*49757Smarc     } else {
1902*49757Smarc 	IF_ENQUEUE(oq, m);	/* otherwise queue it */
1903*49757Smarc 	dda_start(ds, dc);	/* and try to output */
1904*49757Smarc     }
1905*49757Smarc }
1906*49757Smarc 
1907*49757Smarc PRIVATE int
1908*49757Smarc x29_break_reply_is_required(mcp, len)
1909*49757Smarc char           *mcp;
1910*49757Smarc int             len;
1911*49757Smarc {
1912*49757Smarc     mcp++;			/* skip over break indication msg */
1913*49757Smarc     while (len > 1) {		/* while there are parameters left, */
1914*49757Smarc 	if ((*mcp == 8) && (mcp[1] == 1))	/* paramter 8 set to 1? */
1915*49757Smarc 	    return 1;		/* yes */
1916*49757Smarc 	mcp += 2;
1917*49757Smarc 	len -= 2;
1918*49757Smarc     }
1919*49757Smarc     return 0;
1920*49757Smarc }
1921*49757Smarc 
1922*49757Smarc /*
1923*49757Smarc  * Ultrix 3.0 removed the old ttbreakc() kernel routine when moving to
1924*49757Smarc  * a posix compliant driver.  Here it is again, (for our local use only!!!)
1925*49757Smarc  *
1926*49757Smarc  */
1927*49757Smarc #if ACC_ULTRIX >= 30
1928*49757Smarc static int
1929*49757Smarc ttbreakc(c, tp)
1930*49757Smarc register        c;
1931*49757Smarc register struct tty *tp;
1932*49757Smarc {
1933*49757Smarc     return (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOF] ||
1934*49757Smarc 	    c == tp->t_cc[VEOL2] || c == '\r' && (tp->t_flags & CRMOD));
1935*49757Smarc }
1936*49757Smarc #endif
1937*49757Smarc 
1938*49757Smarc 
1939*49757Smarc /*
1940*49757Smarc Revision History:
1941*49757Smarc 
1942*49757Smarc 09-Jun-1988: Unknown (Brad?)
1943*49757Smarc 	Initial implementation.
1944*49757Smarc 15-Feb-1989: Paul Traina
1945*49757Smarc 	Fixed point bug in send_x29_prm_msg
1946*49757Smarc 08-Mar-1989: Steve Johnson
1947*49757Smarc 	Fixed bug in xx_flow logic
1948*49757Smarc 24-May-1989: Paul Traina
1949*49757Smarc 	Upgraded for Ultrix 3.0
1950*49757Smarc 28-May-1989: Paul Traina
1951*49757Smarc 	Added more driver intelligence to disable pad durring call pending
1952*49757Smarc 31-May-1989: Paul Traina
1953*49757Smarc 	Added flexible mapping for # of boards per unit
1954*49757Smarc 04-Jun-1989: Paul Traina
1955*49757Smarc 	Fixed driver to dequeue Q-bit X29 packets from the mbuf chain properly.
1956*49757Smarc 19-Jun-1989: Paul Traina
1957*49757Smarc 	Fixed previous fix-- will need to go over if-elseif logic more
1958*49757Smarc 	carefully to make sure we're doing the right thing.  It should be
1959*49757Smarc 	recoded.
1960*49757Smarc 	Modernized entire debug code suite, changed xxshow functionality to
1961*49757Smarc 	use the uprintf() kernel call to display data on user's terminal for
1962*49757Smarc 	the xxshow hack.
1963*49757Smarc 12-Jul-1989: Paul Traina
1964*49757Smarc 	Changed format of some debug messages.  Removed LOCAL_VOID in
1965*49757Smarc 	favor of PRIVATE routine to aid in debugging.  Simplified some
1966*49757Smarc 	chunky logic.
1967*49757Smarc 18-Jul-1989: Paul Traina
1968*49757Smarc 	Flipped search order for finding a free X29W lcn at RING time.
1969*49757Smarc 	Moved the dc_key.ttyline field out of the union and made it dc_line.
1970*49757Smarc 	This fixed the Dartmouth singleuser bug.
1971*49757Smarc 19-Jul-1989: Paul Traina
1972*49757Smarc 	Changed the packet decode logic in x29_data to immediately process
1973*49757Smarc 	packets with more data pending (i.e. the M-bit) right away, instead
1974*49757Smarc 	of queuing them up.  (Note: it still queues up Q-bit packets)  This
1975*49757Smarc 	may fix the Dartmouth mbuf problem with blasting uploads.
1976*49757Smarc 27-Jul-1989: Paul Traina
1977*49757Smarc 	Removed 8-bit strip in x29_dhandle.
1978*49757Smarc 01-Aug-1989: Paul Traina
1979*49757Smarc 	Added additional two parameters to make_x25_call for userdata/length
1980*49757Smarc 	for merge with new pad software.
1981*49757Smarc 02-Aug-1989: Paul Traina
1982*49757Smarc 	Reinserted 8-bit strip on data received from the net.  (uses
1983*49757Smarc 	PARITY_MASK define for easy change).
1984*49757Smarc 	Fixed forward declaration of ttbreakc().
1985*49757Smarc 	Improved readability of xxshow output.
1986*49757Smarc 	Removed "super" pad code.
1987*49757Smarc 	Modified ps_state to be a real state variable.
1988*49757Smarc 03-Aug-1989: Paul Traina
1989*49757Smarc 	Reversed earlier change to xxselect which didn't pass major #.
1990*49757Smarc 	Modified xxshow output to not use %nd which isn't supported in BSD.
1991*49757Smarc 28-Aug-1989: Paul Traina
1992*49757Smarc 	Changed parameters of make_x25_call -- plug user data field directly.
1993*49757Smarc 14-Nov-1989: Paul Traina
1994*49757Smarc 	Added support for Ultrix 3.1 which uses HUPCL instead of HUPCLS
1995*49757Smarc 	because of that stupid termio interface (sigh).
1996*49757Smarc 16-Nov-1989: Paul Traina
1997*49757Smarc 	Changed parity mask to input_parity_mask, added output_parity_mask.
1998*49757Smarc */
1999