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