1*25224Smckusick /* 2*25224Smckusick * Copyright (c) 1985 Regents of the University of California. 3*25224Smckusick * All rights reserved. The Berkeley software License Agreement 4*25224Smckusick * specifies the terms and conditions for redistribution. 5*25224Smckusick * 6*25224Smckusick * @(#)dmz.c 6.1 (Berkeley) 10/17/85 7*25224Smckusick */ 8*25224Smckusick 9*25224Smckusick /* 10*25224Smckusick * DMZ-32 driver 11*25224Smckusick * HISTORY 12*25224Smckusick * 23-Apr-85 Joe Camaratta (jcc) at Siemens RTL 13*25224Smckusick * Driver for DEC's DMZ32 24-line asynchronous multiplexor. 14*25224Smckusick * Based on Chris Maloney's driver for DEC's DMF32 15*25224Smckusick * NOTE: The modem control routines have NOT been tested yet!!! 16*25224Smckusick * 17*25224Smckusick * 9-Aug-85 Mike Meyer (mwm) at ucb 18*25224Smckusick * Mangled into shape for 4.3. 19*25224Smckusick */ 20*25224Smckusick 21*25224Smckusick #include "dmz.h" 22*25224Smckusick #if NDMZ > 0 23*25224Smckusick 24*25224Smckusick 25*25224Smckusick #include "../machine/pte.h" 26*25224Smckusick 27*25224Smckusick 28*25224Smckusick #include "bk.h" 29*25224Smckusick #include "uba.h" 30*25224Smckusick #include "param.h" 31*25224Smckusick #include "conf.h" 32*25224Smckusick #include "dir.h" 33*25224Smckusick #include "user.h" 34*25224Smckusick #include "ioctl.h" 35*25224Smckusick #include "tty.h" 36*25224Smckusick #include "map.h" 37*25224Smckusick #include "buf.h" 38*25224Smckusick #include "vm.h" 39*25224Smckusick #include "bkmac.h" 40*25224Smckusick #include "clist.h" 41*25224Smckusick #include "file.h" 42*25224Smckusick #include "uio.h" 43*25224Smckusick #include "kernel.h" 44*25224Smckusick 45*25224Smckusick #include "ubareg.h" 46*25224Smckusick #include "ubavar.h" 47*25224Smckusick #include "dmzreg.h" 48*25224Smckusick 49*25224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint(); 50*25224Smckusick struct uba_device *dmzinfo[NDMZ]; 51*25224Smckusick u_short dmzstd[] = {0, 0}; 52*25224Smckusick struct uba_driver dmzdriver = { 53*25224Smckusick dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo 54*25224Smckusick }; 55*25224Smckusick 56*25224Smckusick #define NDMZLINES (NDMZ*24) 57*25224Smckusick 58*25224Smckusick int ttrstrt(); 59*25224Smckusick struct tty dmz_tty[NDMZLINES]; 60*25224Smckusick 61*25224Smckusick int dmzsoftCAR[NDMZ]; 62*25224Smckusick 63*25224Smckusick struct { 64*25224Smckusick char dmz_state; /* dmz state */ 65*25224Smckusick int dmz_count; /* dmz dma count */ 66*25224Smckusick } dmz_softc[NDMZ*24]; 67*25224Smckusick 68*25224Smckusick #define ST_TXOFF (0x01) /* transmission turned off (^S) */ 69*25224Smckusick #define ST_DMA (0x02) /* dma inprogress */ 70*25224Smckusick #define ST_INBUSY (0x04) /* stop transmission in busy */ 71*25224Smckusick 72*25224Smckusick char dmz_speeds[] = { 73*25224Smckusick 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 74*25224Smckusick }; 75*25224Smckusick 76*25224Smckusick #ifndef lint 77*25224Smckusick int ndmz = NDMZLINES; /* Used by pstat/iostat */ 78*25224Smckusick #endif 79*25224Smckusick 80*25224Smckusick short dmzact[NDMZ]; /* Mask of active octets on the dmz */ 81*25224Smckusick int dmzstart(); 82*25224Smckusick 83*25224Smckusick /* 84*25224Smckusick * SILO_TIMEOUT represents the number of milliseconds characters can sit 85*25224Smckusick * in the input silo without causing an interrupt. If data overruns or 86*25224Smckusick * slow XON/XOFF occur, set it lower but AT LEAST equal to 1. 87*25224Smckusick */ 88*25224Smckusick #define SILO_TIMEOUT (3) 89*25224Smckusick 90*25224Smckusick /* 91*25224Smckusick * DO_DMA_COUNT represents the threshold of the number of output 92*25224Smckusick * characters beyond which the driver uses DMA mode. 93*25224Smckusick */ 94*25224Smckusick #define DO_DMA_COUNT (10) 95*25224Smckusick 96*25224Smckusick #define TRUE (1) 97*25224Smckusick #define FALSE (0) 98*25224Smckusick 99*25224Smckusick static int cbase[NUBA]; /* base address in unibus map */ 100*25224Smckusick int dmz_ubinfo[NUBA]; /* info about allocated unibus map */ 101*25224Smckusick 102*25224Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x) - (char *)cfree)) 103*25224Smckusick 104*25224Smckusick /* These flags are for debugging purposes only */ 105*25224Smckusick int dmz_dma_on = 1; 106*25224Smckusick int dmz_debug_level; 107*25224Smckusick 108*25224Smckusick dmzprobe(reg) 109*25224Smckusick caddr_t reg; 110*25224Smckusick { 111*25224Smckusick register int br, cvec; 112*25224Smckusick register struct dmzdevice *dmz_addr; 113*25224Smckusick register unsigned int a; 114*25224Smckusick 115*25224Smckusick dmz_addr = (struct dmzdevice *)reg; 116*25224Smckusick 117*25224Smckusick #ifdef lint 118*25224Smckusick br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0); 119*25224Smckusick dmzrinta(0); dmzrintb(0); dmzrintc(0); 120*25224Smckusick #endif 121*25224Smckusick 122*25224Smckusick br = 0x15; 123*25224Smckusick 124*25224Smckusick a = dmz_addr->dmz_config; 125*25224Smckusick if (((a>>12) & ~DMZ_INTERFACE) != 0) { 126*25224Smckusick printf(" Unknown interface type\n"); 127*25224Smckusick return (0); 128*25224Smckusick } 129*25224Smckusick if (((a>>8) & DMZ_NOC_MASK) != 3) { 130*25224Smckusick printf(" Not all octets are available\n"); 131*25224Smckusick return (0); 132*25224Smckusick } 133*25224Smckusick 134*25224Smckusick cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6); 135*25224Smckusick dmz_addr->dmz_config = cvec >> 2; 136*25224Smckusick 137*25224Smckusick return (sizeof(struct dmzdevice)); 138*25224Smckusick } 139*25224Smckusick 140*25224Smckusick dmzattach(ui) 141*25224Smckusick struct uba_device *ui; 142*25224Smckusick { 143*25224Smckusick dmzsoftCAR[ui->ui_unit] = ui->ui_flags; 144*25224Smckusick return; 145*25224Smckusick } 146*25224Smckusick 147*25224Smckusick /* ARGSUSED */ 148*25224Smckusick dmzopen(device, flag) 149*25224Smckusick dev_t device; 150*25224Smckusick int flag; 151*25224Smckusick { 152*25224Smckusick register struct tty *tp; 153*25224Smckusick register int unit, controller; 154*25224Smckusick register struct dmzdevice *dmz_addr; 155*25224Smckusick register struct uba_device *ui; 156*25224Smckusick int priority; 157*25224Smckusick int xstatus; 158*25224Smckusick int octet; 159*25224Smckusick 160*25224Smckusick unit = minor(device); 161*25224Smckusick controller = DMZ(unit); 162*25224Smckusick octet = OCTET(unit); 163*25224Smckusick 164*25224Smckusick if (unit >= NDMZLINES || 165*25224Smckusick (ui = dmzinfo[controller]) == 0 || 166*25224Smckusick ui->ui_alive == 0) 167*25224Smckusick return (ENXIO); 168*25224Smckusick 169*25224Smckusick tp = &dmz_tty[unit]; 170*25224Smckusick 171*25224Smckusick if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0) 172*25224Smckusick return (EBUSY); 173*25224Smckusick 174*25224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 175*25224Smckusick tp->t_addr = (caddr_t)dmz_addr; 176*25224Smckusick tp->t_oproc = dmzstart; 177*25224Smckusick tp->t_state |= TS_WOPEN; 178*25224Smckusick 179*25224Smckusick /* 180*25224Smckusick * Set up Unibus map registers. Block uba resets, which can 181*25224Smckusick * clear the state. 182*25224Smckusick */ 183*25224Smckusick priority = spl5(); 184*25224Smckusick if (dmz_ubinfo[ui->ui_ubanum] == 0) { 185*25224Smckusick dmz_ubinfo[ui->ui_ubanum] = 186*25224Smckusick uballoc(ui->ui_ubanum, (caddr_t)cfree, 187*25224Smckusick nclist * sizeof(struct cblock), 0); 188*25224Smckusick if (dmz_ubinfo[ui->ui_ubanum] == 0) { 189*25224Smckusick splx(priority); 190*25224Smckusick printf("dmz: insufficient unibus map regs\n"); 191*25224Smckusick return (-1); /* Is this the right thing to return? */ 192*25224Smckusick } 193*25224Smckusick cbase[ui->ui_ubanum] = dmz_ubinfo[ui->ui_ubanum] & 0x3ffff; 194*25224Smckusick } 195*25224Smckusick 196*25224Smckusick if ((dmzact[controller] & (1 << octet)) == 0) { 197*25224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 198*25224Smckusick dmzact[controller] |= 1 << octet; 199*25224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 200*25224Smckusick } 201*25224Smckusick 202*25224Smckusick splx(priority); 203*25224Smckusick 204*25224Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 205*25224Smckusick ttychars(tp); 206*25224Smckusick if (tp->t_ispeed == 0) { 207*25224Smckusick tp->t_ispeed = tp->t_ospeed = B300; 208*25224Smckusick tp->t_flags = ODDP | EVENP | ECHO; 209*25224Smckusick } 210*25224Smckusick dmzparam(unit); 211*25224Smckusick dmz_softc[unit].dmz_state = 0; 212*25224Smckusick } 213*25224Smckusick 214*25224Smckusick /* 215*25224Smckusick * Wait for carrier, then process line discipline specific open. 216*25224Smckusick */ 217*25224Smckusick if ((dmzmctl(device, DMZ_ON, DMSET) & (DMZ_CAR << 8)) || 218*25224Smckusick (dmzsoftCAR[controller] & (1 << (unit % 24)))) 219*25224Smckusick tp->t_state |= TS_CARR_ON; 220*25224Smckusick priority = spl5(); 221*25224Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 222*25224Smckusick tp->t_state |= TS_WOPEN; 223*25224Smckusick sleep((caddr_t) &tp->t_rawq, TTIPRI); 224*25224Smckusick } 225*25224Smckusick splx(priority); 226*25224Smckusick 227*25224Smckusick xstatus = (*linesw[tp->t_line].l_open)(device, tp); 228*25224Smckusick return (xstatus); 229*25224Smckusick } 230*25224Smckusick 231*25224Smckusick dmzparam(unit) 232*25224Smckusick register int unit; 233*25224Smckusick { 234*25224Smckusick register struct tty *tp; 235*25224Smckusick register struct dmzdevice *dmz_addr; 236*25224Smckusick register int line_parameters, line_control; 237*25224Smckusick register int octet; 238*25224Smckusick int priority; 239*25224Smckusick 240*25224Smckusick octet = OCTET(unit); 241*25224Smckusick 242*25224Smckusick tp = &dmz_tty[unit]; 243*25224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 244*25224Smckusick 245*25224Smckusick priority = spl5(); 246*25224Smckusick if ((tp->t_ispeed) == 0) { 247*25224Smckusick tp->t_state |= TS_HUPCLS; 248*25224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 249*25224Smckusick splx(priority); 250*25224Smckusick return; 251*25224Smckusick } 252*25224Smckusick 253*25224Smckusick line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8); 254*25224Smckusick line_control = DMZ_LCE; 255*25224Smckusick 256*25224Smckusick if ((tp->t_ispeed) == B134) 257*25224Smckusick line_parameters |= DMZ_6BT | DMZ_PEN; 258*25224Smckusick else if (tp->t_flags & (RAW | LITOUT)) 259*25224Smckusick line_parameters |= DMZ_8BT; 260*25224Smckusick else 261*25224Smckusick line_parameters |= DMZ_7BT | DMZ_PEN; 262*25224Smckusick 263*25224Smckusick if (tp->t_flags & EVENP) 264*25224Smckusick line_parameters |= DMZ_EPR; 265*25224Smckusick if ((tp->t_ospeed) == B110) 266*25224Smckusick line_parameters |= DMZ_SCD; 267*25224Smckusick 268*25224Smckusick line_parameters |= (unit & 07); 269*25224Smckusick 270*25224Smckusick dmz_addr->octet[octet].octet_lprm = line_parameters; 271*25224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 272*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 273*25224Smckusick (dmz_addr->octet[octet].octet_lctmr | (line_control & 0xff)); 274*25224Smckusick 275*25224Smckusick splx(priority); 276*25224Smckusick return; 277*25224Smckusick } 278*25224Smckusick 279*25224Smckusick /* ARGSUSED */ 280*25224Smckusick dmzclose(device, flag) 281*25224Smckusick dev_t device; 282*25224Smckusick int flag; 283*25224Smckusick { 284*25224Smckusick register struct tty *tp; 285*25224Smckusick register int unit; 286*25224Smckusick 287*25224Smckusick unit = minor(device); 288*25224Smckusick tp = &dmz_tty[unit]; 289*25224Smckusick 290*25224Smckusick /* 291*25224Smckusick * Break, hang-up and close the modem. 292*25224Smckusick */ 293*25224Smckusick (void) dmzmctl(unit, DMZ_BRK, DMBIC); 294*25224Smckusick if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 295*25224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 296*25224Smckusick ttyclose(tp); 297*25224Smckusick return; 298*25224Smckusick } 299*25224Smckusick 300*25224Smckusick dmzreset(uban) 301*25224Smckusick int uban; 302*25224Smckusick { 303*25224Smckusick register int controller, unit; 304*25224Smckusick register struct tty *tp; 305*25224Smckusick register struct uba_device *ui; 306*25224Smckusick register struct dmzdevice *dmz_addr; 307*25224Smckusick int i; 308*25224Smckusick int octet; 309*25224Smckusick 310*25224Smckusick if (dmz_ubinfo[uban] == 0) 311*25224Smckusick return; 312*25224Smckusick 313*25224Smckusick dmz_ubinfo[uban] = uballoc(uban, (caddr_t) cfree, nclist * sizeof(struct cblock), 0); 314*25224Smckusick cbase[uban] = dmz_ubinfo[uban] & 0x3ffff; 315*25224Smckusick 316*25224Smckusick for (controller = 0; controller < NDMZ; controller++) { 317*25224Smckusick ui = dmzinfo[controller]; 318*25224Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 319*25224Smckusick continue; 320*25224Smckusick printf("dmz%d ", controller); 321*25224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 322*25224Smckusick 323*25224Smckusick for (octet = 0; octet < 3; octet++) 324*25224Smckusick if ((dmzact[controller] & (1 << octet)) != 0) { 325*25224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 326*25224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 327*25224Smckusick } 328*25224Smckusick 329*25224Smckusick unit = controller * 24; 330*25224Smckusick 331*25224Smckusick /* 332*25224Smckusick * If a unit is open or waiting for open to complete, 333*25224Smckusick * reset it. 334*25224Smckusick */ 335*25224Smckusick for (i = 0; i < 24; i++) { 336*25224Smckusick dmz_softc[unit].dmz_state = 0; 337*25224Smckusick tp = &dmz_tty[unit]; 338*25224Smckusick if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) { 339*25224Smckusick dmzparam(unit); 340*25224Smckusick (void) dmzmctl(unit, DMZ_ON, DMSET); 341*25224Smckusick tp->t_state &= ~TS_BUSY; 342*25224Smckusick dmzstart(tp); 343*25224Smckusick } 344*25224Smckusick unit++; 345*25224Smckusick } 346*25224Smckusick } 347*25224Smckusick return; 348*25224Smckusick } 349*25224Smckusick 350*25224Smckusick dmzread(device, uio) 351*25224Smckusick dev_t device; 352*25224Smckusick struct uio *uio; 353*25224Smckusick { 354*25224Smckusick register struct tty *tp; 355*25224Smckusick int xstatus; 356*25224Smckusick 357*25224Smckusick tp = &dmz_tty[minor(device)]; 358*25224Smckusick xstatus = (*linesw[tp->t_line].l_read)(tp, uio); 359*25224Smckusick return (xstatus); 360*25224Smckusick } 361*25224Smckusick 362*25224Smckusick dmzwrite(device, uio) 363*25224Smckusick dev_t device; 364*25224Smckusick struct uio *uio; 365*25224Smckusick { 366*25224Smckusick register struct tty *tp; 367*25224Smckusick int xstatus; 368*25224Smckusick 369*25224Smckusick tp = &dmz_tty[minor(device)]; 370*25224Smckusick xstatus = (*linesw[tp->t_line].l_write)(tp, uio); 371*25224Smckusick return (xstatus); 372*25224Smckusick } 373*25224Smckusick 374*25224Smckusick dmzrinta(controller) 375*25224Smckusick int controller; 376*25224Smckusick { 377*25224Smckusick dmzrint(controller, 0); 378*25224Smckusick } 379*25224Smckusick 380*25224Smckusick dmzrintb(controller) 381*25224Smckusick int controller; 382*25224Smckusick { 383*25224Smckusick dmzrint(controller, 1); 384*25224Smckusick } 385*25224Smckusick 386*25224Smckusick dmzrintc(controller) 387*25224Smckusick int controller; 388*25224Smckusick { 389*25224Smckusick dmzrint(controller, 2); 390*25224Smckusick } 391*25224Smckusick 392*25224Smckusick dmzrint(controller, octet) 393*25224Smckusick int controller; 394*25224Smckusick register int octet; 395*25224Smckusick { 396*25224Smckusick register struct tty *tp; 397*25224Smckusick register int character; 398*25224Smckusick register struct dmzdevice *dmz_addr; 399*25224Smckusick register struct tty *tp0; 400*25224Smckusick register int unit; 401*25224Smckusick register struct uba_device *ui; 402*25224Smckusick int overrun, priority; 403*25224Smckusick 404*25224Smckusick overrun = 0; 405*25224Smckusick ui = dmzinfo[controller]; 406*25224Smckusick if (ui == 0 || ui->ui_alive == 0) 407*25224Smckusick return; 408*25224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 409*25224Smckusick tp0 = &dmz_tty[controller * 24]; 410*25224Smckusick 411*25224Smckusick while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) { 412*25224Smckusick unit = (character >> 8) & 07; /* unit is bits 8-10 of rb */ 413*25224Smckusick tp = tp0 + (octet * 8 + unit); 414*25224Smckusick 415*25224Smckusick if (character & DMZ_DSC) { 416*25224Smckusick if ((dmzsoftCAR[controller] & (1 << (octet * 8 + unit))) == 0) { 417*25224Smckusick priority = spl5(); 418*25224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | unit; 419*25224Smckusick if (dmz_addr->octet[octet].octet_rms & DMZ_CAR && 420*25224Smckusick (tp->t_state & TS_CARR_ON) == 0) { 421*25224Smckusick tp->t_state |= TS_CARR_ON; 422*25224Smckusick wakeup((caddr_t) &tp->t_rawq); 423*25224Smckusick } else { 424*25224Smckusick if (tp->t_state & TS_CARR_ON) { 425*25224Smckusick gsignal(tp->t_pgrp, SIGHUP); 426*25224Smckusick gsignal(tp->t_pgrp, SIGCONT); 427*25224Smckusick dmz_addr->octet[octet].octet_csr = 428*25224Smckusick DMZ_IE | IR_LCTMR | unit; 429*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 430*25224Smckusick dmz_addr->octet[octet].octet_lctmr & 431*25224Smckusick ((DMZ_OFF<<8) | 0xff); 432*25224Smckusick ttyflush(tp, FREAD|FWRITE); 433*25224Smckusick } 434*25224Smckusick tp->t_state &= ~TS_CARR_ON; 435*25224Smckusick } 436*25224Smckusick splx(priority); 437*25224Smckusick } 438*25224Smckusick continue; 439*25224Smckusick } 440*25224Smckusick 441*25224Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 442*25224Smckusick wakeup((caddr_t) tp); 443*25224Smckusick continue; 444*25224Smckusick } 445*25224Smckusick 446*25224Smckusick if (character & DMZ_PE) { 447*25224Smckusick if ((tp->t_flags & (EVENP | ODDP)) == EVENP || 448*25224Smckusick (tp->t_flags & (EVENP | ODDP)) == ODDP) 449*25224Smckusick continue; 450*25224Smckusick } 451*25224Smckusick 452*25224Smckusick if ((character & DMZ_DO) && overrun == 0) { 453*25224Smckusick printf("dmz%d: silo overflow\n", controller); 454*25224Smckusick overrun = 1; 455*25224Smckusick } 456*25224Smckusick 457*25224Smckusick if (character & DMZ_FE) { 458*25224Smckusick if (tp->t_flags & RAW) 459*25224Smckusick character = 0; 460*25224Smckusick else 461*25224Smckusick character = tp->t_intrc; 462*25224Smckusick } 463*25224Smckusick 464*25224Smckusick (*linesw[tp->t_line].l_rint)(character, tp); 465*25224Smckusick } 466*25224Smckusick 467*25224Smckusick return; 468*25224Smckusick } 469*25224Smckusick 470*25224Smckusick dmzxinta(controller) 471*25224Smckusick int controller; 472*25224Smckusick { 473*25224Smckusick dmzxint(controller, 0); 474*25224Smckusick } 475*25224Smckusick 476*25224Smckusick dmzxintb(controller) 477*25224Smckusick int controller; 478*25224Smckusick { 479*25224Smckusick dmzxint(controller, 1); 480*25224Smckusick } 481*25224Smckusick 482*25224Smckusick dmzxintc(controller) 483*25224Smckusick int controller; 484*25224Smckusick { 485*25224Smckusick dmzxint(controller, 2); 486*25224Smckusick } 487*25224Smckusick 488*25224Smckusick dmzxint(controller, octet) 489*25224Smckusick int controller; 490*25224Smckusick register int octet; 491*25224Smckusick { 492*25224Smckusick register struct tty *tp; 493*25224Smckusick register struct dmzdevice *dmz_addr; 494*25224Smckusick register struct uba_device *ui; 495*25224Smckusick register int unit, t; 496*25224Smckusick int priority; 497*25224Smckusick 498*25224Smckusick ui = dmzinfo[controller]; 499*25224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 500*25224Smckusick 501*25224Smckusick priority = spl5(); 502*25224Smckusick 503*25224Smckusick while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) { 504*25224Smckusick unit = controller * 24 + (octet * 8 + ((t>>8) & 07)); 505*25224Smckusick tp = &dmz_tty[unit]; 506*25224Smckusick tp->t_state &= ~TS_BUSY; 507*25224Smckusick 508*25224Smckusick if (t & DMZ_NXM) 509*25224Smckusick printf("dmz%d: NXM line %d\n", controller, 510*25224Smckusick octet * 8 + (unit & 07)); 511*25224Smckusick 512*25224Smckusick if (tp->t_state & TS_FLUSH) { 513*25224Smckusick tp->t_state &= ~TS_FLUSH; 514*25224Smckusick dmz_addr->octet[octet].octet_csr = 515*25224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 516*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 517*25224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 518*25224Smckusick } else 519*25224Smckusick if (dmz_softc[unit].dmz_state & ST_DMA) 520*25224Smckusick ndflush(&tp->t_outq, dmz_softc[unit].dmz_count); 521*25224Smckusick dmz_softc[unit].dmz_state = 0; 522*25224Smckusick 523*25224Smckusick if (tp->t_line) 524*25224Smckusick (*linesw[tp->t_line].l_start)(tp); 525*25224Smckusick else 526*25224Smckusick dmzstart(tp); 527*25224Smckusick } 528*25224Smckusick 529*25224Smckusick splx(priority); 530*25224Smckusick return; 531*25224Smckusick } 532*25224Smckusick 533*25224Smckusick dmzstart(tp) 534*25224Smckusick register struct tty *tp; 535*25224Smckusick { 536*25224Smckusick register struct dmzdevice *dmz_addr; 537*25224Smckusick register int unit, nch, room; 538*25224Smckusick int controller, octet; 539*25224Smckusick int priority, car, use_dma; 540*25224Smckusick register int i; 541*25224Smckusick register char *cp; 542*25224Smckusick 543*25224Smckusick unit = minor(tp->t_dev); 544*25224Smckusick controller = DMZ(unit); 545*25224Smckusick octet = OCTET(unit); 546*25224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 547*25224Smckusick 548*25224Smckusick priority = spl5(); 549*25224Smckusick 550*25224Smckusick if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 551*25224Smckusick goto out; 552*25224Smckusick 553*25224Smckusick /* 554*25224Smckusick * If the transmitter has been disabled, reenable it. 555*25224Smckusick * If the transmitter was disabled before the xint (the 556*25224Smckusick * ST_INBUSY was still on), then reset the BUSY state and 557*25224Smckusick * we will wait for the interrupt. If !TS_BUSY, we already 558*25224Smckusick * saw the interrupt so we can start another transmission. 559*25224Smckusick */ 560*25224Smckusick if (dmz_softc[unit].dmz_state & ST_TXOFF) { 561*25224Smckusick dmz_addr->octet[octet].octet_csr = 562*25224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 563*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 564*25224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 565*25224Smckusick dmz_softc[unit].dmz_state &= ~ST_TXOFF; 566*25224Smckusick if (dmz_softc[unit].dmz_state & ST_INBUSY) { 567*25224Smckusick dmz_softc[unit].dmz_state &= ~ST_INBUSY; 568*25224Smckusick tp->t_state |= TS_BUSY; 569*25224Smckusick goto out; 570*25224Smckusick } 571*25224Smckusick } 572*25224Smckusick 573*25224Smckusick if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 574*25224Smckusick if (tp->t_state & TS_ASLEEP) { 575*25224Smckusick tp->t_state &= ~TS_ASLEEP; 576*25224Smckusick wakeup((caddr_t)&tp->t_outq); 577*25224Smckusick } 578*25224Smckusick if (tp->t_wsel) { 579*25224Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 580*25224Smckusick tp->t_wsel = 0; 581*25224Smckusick tp->t_state &= ~TS_WCOLL; 582*25224Smckusick } 583*25224Smckusick } 584*25224Smckusick 585*25224Smckusick if (tp->t_outq.c_cc == 0) 586*25224Smckusick goto out; 587*25224Smckusick if (tp->t_flags & (RAW | LITOUT)) 588*25224Smckusick nch = ndqb(&tp->t_outq, 0); 589*25224Smckusick else { 590*25224Smckusick nch = ndqb(&tp->t_outq, 0200); 591*25224Smckusick if (nch == 0) { 592*25224Smckusick nch = getc(&tp->t_outq); 593*25224Smckusick timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6); 594*25224Smckusick tp->t_state |= TS_TIMEOUT; 595*25224Smckusick goto out; 596*25224Smckusick } 597*25224Smckusick } 598*25224Smckusick 599*25224Smckusick /* 600*25224Smckusick * Should we use DMA or SILO mode? 601*25224Smckusick * If nch is greater than DO_DMA_COUNT then DMA. 602*25224Smckusick */ 603*25224Smckusick if (nch) { 604*25224Smckusick dmz_addr->octet[octet].octet_csr = 605*25224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 606*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 607*25224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 608*25224Smckusick tp->t_state |= TS_BUSY; 609*25224Smckusick 610*25224Smckusick use_dma = FALSE; 611*25224Smckusick room = DMZ_SIZ; 612*25224Smckusick 613*25224Smckusick if (nch > DO_DMA_COUNT) 614*25224Smckusick use_dma = TRUE; 615*25224Smckusick 616*25224Smckusick if (use_dma && dmz_dma_on) { 617*25224Smckusick car = UBACVT(tp->t_outq.c_cf, 618*25224Smckusick dmzinfo[controller]->ui_ubanum); 619*25224Smckusick dmz_softc[unit].dmz_count = nch; 620*25224Smckusick dmz_softc[unit].dmz_state |= ST_DMA; 621*25224Smckusick dmz_addr->octet[octet].octet_csr = 622*25224Smckusick DMZ_IE | IR_TBA | (unit & 07); 623*25224Smckusick dmz_addr->octet[octet].octet_tba = car; 624*25224Smckusick dmz_addr->octet[octet].octet_tcc = 625*25224Smckusick ((car >> 2) & 0xc000) | nch; 626*25224Smckusick } else { 627*25224Smckusick dmz_softc[unit].dmz_state &= ~ST_DMA; 628*25224Smckusick cp = tp->t_outq.c_cf; 629*25224Smckusick nch = MIN(nch, room); 630*25224Smckusick dmz_addr->octet[octet].octet_csr = 631*25224Smckusick DMZ_IE | IR_TBUF | (unit & 07); 632*25224Smckusick for (i = 0; i < nch; i++) 633*25224Smckusick dmz_addr->octet[octet].octet_tbf = *cp++ ; 634*25224Smckusick ndflush(&tp->t_outq, nch); 635*25224Smckusick } 636*25224Smckusick } 637*25224Smckusick 638*25224Smckusick out: 639*25224Smckusick splx(priority); 640*25224Smckusick return; 641*25224Smckusick } 642*25224Smckusick 643*25224Smckusick /* ARGSUSED */ 644*25224Smckusick dmzstop(tp, flag) 645*25224Smckusick register struct tty *tp; 646*25224Smckusick { 647*25224Smckusick register struct dmzdevice *dmz_addr; 648*25224Smckusick register int unit, priority, octet; 649*25224Smckusick 650*25224Smckusick priority = spl5(); 651*25224Smckusick dmz_addr = (struct dmzdevice *) tp->t_addr; 652*25224Smckusick unit = minor(tp->t_dev); 653*25224Smckusick octet = OCTET(unit); 654*25224Smckusick 655*25224Smckusick dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE; 656*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 657*25224Smckusick (dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE); 658*25224Smckusick dmz_softc[unit].dmz_state |= ST_TXOFF; 659*25224Smckusick if ((tp->t_state & TS_TTSTOP) == 0) { 660*25224Smckusick tp->t_state |= (TS_FLUSH | TS_BUSY); 661*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 662*25224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_FLS); 663*25224Smckusick } else if (tp->t_state & TS_BUSY) { 664*25224Smckusick dmz_softc[unit].dmz_state |= ST_INBUSY; 665*25224Smckusick tp->t_state &= ~TS_BUSY; 666*25224Smckusick } 667*25224Smckusick 668*25224Smckusick splx(priority); 669*25224Smckusick return; 670*25224Smckusick } 671*25224Smckusick 672*25224Smckusick /* ARGSUSED */ 673*25224Smckusick dmzioctl(device, command, data, flag) 674*25224Smckusick dev_t device; 675*25224Smckusick caddr_t data; 676*25224Smckusick { 677*25224Smckusick register struct tty *tp; 678*25224Smckusick register int unit; 679*25224Smckusick int error; 680*25224Smckusick 681*25224Smckusick unit = minor(device); 682*25224Smckusick tp = &dmz_tty[unit]; 683*25224Smckusick 684*25224Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag); 685*25224Smckusick if (error >= 0) 686*25224Smckusick return (error); 687*25224Smckusick error = ttioctl(tp, command, data, flag); 688*25224Smckusick if (error >= 0) { 689*25224Smckusick if (command == TIOCSETP || command == TIOCSETN) 690*25224Smckusick dmzparam(unit); 691*25224Smckusick return (error); 692*25224Smckusick } 693*25224Smckusick 694*25224Smckusick switch (command) { 695*25224Smckusick case TIOCSBRK: 696*25224Smckusick (void) dmzmctl(device, DMZ_BRK, DMBIS); 697*25224Smckusick break; 698*25224Smckusick case TIOCCBRK: 699*25224Smckusick (void) dmzmctl(device, DMZ_BRK, DMBIC); 700*25224Smckusick break; 701*25224Smckusick case TIOCSDTR: 702*25224Smckusick (void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIS); 703*25224Smckusick break; 704*25224Smckusick case TIOCCDTR: 705*25224Smckusick (void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIC); 706*25224Smckusick break; 707*25224Smckusick case TIOCMSET: 708*25224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMSET); 709*25224Smckusick break; 710*25224Smckusick case TIOCMBIS: 711*25224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMBIS); 712*25224Smckusick break; 713*25224Smckusick case TIOCMBIC: 714*25224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMBIC); 715*25224Smckusick break; 716*25224Smckusick case TIOCMGET: 717*25224Smckusick *(int *)data = dmztodm(dmzmctl(device, 0, DMGET)); 718*25224Smckusick break; 719*25224Smckusick default: 720*25224Smckusick return (ENOTTY); 721*25224Smckusick } 722*25224Smckusick return (0); 723*25224Smckusick } 724*25224Smckusick 725*25224Smckusick dmzmctl(device, bits, how) 726*25224Smckusick dev_t device; 727*25224Smckusick int bits, how; 728*25224Smckusick { 729*25224Smckusick register struct dmzdevice *dmz_addr; 730*25224Smckusick register int unit, modem_status, line_control; 731*25224Smckusick register int temp; 732*25224Smckusick int priority; 733*25224Smckusick int octet; 734*25224Smckusick 735*25224Smckusick unit = minor(device); 736*25224Smckusick octet = OCTET(unit); 737*25224Smckusick dmz_addr = (struct dmzdevice *) dmz_tty[unit].t_addr; 738*25224Smckusick 739*25224Smckusick priority = spl5(); 740*25224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | (unit & 07); 741*25224Smckusick modem_status = dmz_addr->octet[octet].octet_rms << 8; 742*25224Smckusick 743*25224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 744*25224Smckusick temp = dmz_addr->octet[octet].octet_lctmr; 745*25224Smckusick modem_status |= ((temp>>8) & (0x1f)); 746*25224Smckusick line_control = (temp & (0x1f)); 747*25224Smckusick 748*25224Smckusick if (line_control & DMZ_BRK) 749*25224Smckusick modem_status |= DMZ_BRK; 750*25224Smckusick 751*25224Smckusick switch (how) { 752*25224Smckusick case DMSET: 753*25224Smckusick modem_status = (modem_status & 0xff00) | bits; 754*25224Smckusick break; 755*25224Smckusick case DMBIS: 756*25224Smckusick modem_status |= bits; 757*25224Smckusick break; 758*25224Smckusick case DMBIC: 759*25224Smckusick modem_status &= ~bits; 760*25224Smckusick break; 761*25224Smckusick case DMGET: 762*25224Smckusick (void) splx(priority); 763*25224Smckusick return (modem_status); 764*25224Smckusick } 765*25224Smckusick 766*25224Smckusick if (modem_status & DMZ_BRK) 767*25224Smckusick line_control |= DMZ_RBK; 768*25224Smckusick else 769*25224Smckusick line_control &= ~DMZ_RBK; 770*25224Smckusick modem_status &= ~DMZ_BRK; 771*25224Smckusick 772*25224Smckusick dmz_addr->octet[octet].octet_csr = 773*25224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 774*25224Smckusick dmz_addr->octet[octet].octet_lctmr = 775*25224Smckusick ((modem_status & 0x1f) << 8) | (line_control & 0x3f); 776*25224Smckusick 777*25224Smckusick (void) splx(priority); 778*25224Smckusick return (modem_status); 779*25224Smckusick } 780*25224Smckusick 781*25224Smckusick /* 782*25224Smckusick * Routine to convert modem status from dm to dmz format. 783*25224Smckusick * Pull bits 1 & 3 through unchanged. If dm secondary transmit bit is set, 784*25224Smckusick * and/or dm request to send bit is set, and/or dm user modem signal bit 785*25224Smckusick * is set, set the corresponding dmz bits. 786*25224Smckusick */ 787*25224Smckusick dmtodmz(bits) 788*25224Smckusick register int bits; 789*25224Smckusick { 790*25224Smckusick register int b; 791*25224Smckusick 792*25224Smckusick b = bits & 012; 793*25224Smckusick if (bits & DM_ST) 794*25224Smckusick b |= DMZ_RAT; 795*25224Smckusick if (bits & DM_RTS) 796*25224Smckusick b |= DMZ_RTS; 797*25224Smckusick if (bits & DM_USR) 798*25224Smckusick b |= DMZ_USW; 799*25224Smckusick return (b); 800*25224Smckusick } 801*25224Smckusick 802*25224Smckusick /* 803*25224Smckusick * Routine to convert modem status from dmz to dm format. Pull bits 1 & 3 804*25224Smckusick * through unchanged. Pull bits 11 - 15 through as bits 4 - 8 and set bit 805*25224Smckusick * 0 to dm line enable. If dmz user modem signal bit set, and/or dmz 806*25224Smckusick * request to send bit set, then set the corresponding dm bit also. 807*25224Smckusick */ 808*25224Smckusick dmztodm(bits) 809*25224Smckusick register int bits; 810*25224Smckusick { 811*25224Smckusick register int b; 812*25224Smckusick 813*25224Smckusick b = (bits & 012) | ((bits >> 7) & 0760) | DM_LE; 814*25224Smckusick if (bits & DMZ_USR) 815*25224Smckusick b |= DM_USR; 816*25224Smckusick if (bits & DMZ_RTS) 817*25224Smckusick b |= DM_RTS; 818*25224Smckusick return (b); 819*25224Smckusick } 820*25224Smckusick #endif 821