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