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