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