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