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*/
xxopen(dev,flag)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*/
xxclose(dev,flag,mode,p)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
xxread(dev,uio)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
xxwrite(dev,uio)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
xxioctl(dev,cmd,data,flag)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*/
xxparam(dev)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
xxstart(tp)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*/
xxreset(uban)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
xxselect(dev,rw)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
x29_supr(ds,p)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
xx_tp_hangup(ds,dc)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
x29_data(ds,hc,cc,cnt,subcc)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
x29_dhandle(ds,dc,restart)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
xx_qbit_msg(tp,unit,msg)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
xxcntl(tp,c,unit)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
x29_init(unit,active)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
xxclear(unit)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
xxshow()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
xxpadhandle(ds,tp,pi)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
xxpadparse(ds,pi,tp)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
xxpadcall(ds,addr,tp)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
xxpadmsg(s,tp)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 */
send_x29_param_msg(ds,dc,type,msg,len)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
x29_break_reply_is_required(mcp,len)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
ttbreakc(c,tp)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