125224Smckusick /* 225224Smckusick * Copyright (c) 1985 Regents of the University of California. 325224Smckusick * All rights reserved. The Berkeley software License Agreement 425224Smckusick * specifies the terms and conditions for redistribution. 525224Smckusick * 6*26837Skarels * @(#)dmz.c 6.6 (Berkeley) 03/13/86 725224Smckusick */ 825224Smckusick 925224Smckusick /* 1025224Smckusick * DMZ-32 driver 1125224Smckusick * HISTORY 1225224Smckusick * 23-Apr-85 Joe Camaratta (jcc) at Siemens RTL 1325224Smckusick * Driver for DEC's DMZ32 24-line asynchronous multiplexor. 1425224Smckusick * Based on Chris Maloney's driver for DEC's DMF32 1525224Smckusick * 1625224Smckusick * 9-Aug-85 Mike Meyer (mwm) at ucb 1725224Smckusick * Mangled into shape for 4.3. 1825224Smckusick */ 1925224Smckusick 2025224Smckusick #include "dmz.h" 2125224Smckusick #if NDMZ > 0 2225224Smckusick 2325224Smckusick 2425224Smckusick #include "../machine/pte.h" 2525224Smckusick 2625224Smckusick 2725224Smckusick #include "bk.h" 2825224Smckusick #include "uba.h" 2925224Smckusick #include "param.h" 3025224Smckusick #include "conf.h" 3125224Smckusick #include "dir.h" 3225224Smckusick #include "user.h" 33*26837Skarels #include "proc.h" 3425224Smckusick #include "ioctl.h" 3525224Smckusick #include "tty.h" 3625224Smckusick #include "map.h" 3725224Smckusick #include "buf.h" 3825224Smckusick #include "vm.h" 3925224Smckusick #include "bkmac.h" 4025224Smckusick #include "clist.h" 4125224Smckusick #include "file.h" 4225224Smckusick #include "uio.h" 4325224Smckusick #include "kernel.h" 4425435Skarels #include "syslog.h" 4525224Smckusick 4625224Smckusick #include "ubareg.h" 4725224Smckusick #include "ubavar.h" 4825224Smckusick #include "dmzreg.h" 4925655Skarels #include "dmreg.h" 5025224Smckusick 5125224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint(); 5225224Smckusick struct uba_device *dmzinfo[NDMZ]; 5325224Smckusick u_short dmzstd[] = {0, 0}; 5425224Smckusick struct uba_driver dmzdriver = { 5525224Smckusick dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo 5625224Smckusick }; 5725224Smckusick 5825224Smckusick #define NDMZLINES (NDMZ*24) 5925224Smckusick 6025224Smckusick int ttrstrt(); 6125224Smckusick struct tty dmz_tty[NDMZLINES]; 6225224Smckusick 6325224Smckusick int dmzsoftCAR[NDMZ]; 6425224Smckusick 6525224Smckusick struct { 6625224Smckusick char dmz_state; /* dmz state */ 6725224Smckusick int dmz_count; /* dmz dma count */ 6825224Smckusick } dmz_softc[NDMZ*24]; 6925224Smckusick 7025224Smckusick #define ST_TXOFF (0x01) /* transmission turned off (^S) */ 7125224Smckusick #define ST_DMA (0x02) /* dma inprogress */ 7225224Smckusick #define ST_INBUSY (0x04) /* stop transmission in busy */ 7325224Smckusick 7425224Smckusick char dmz_speeds[] = { 7525224Smckusick 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 7625224Smckusick }; 7725224Smckusick 7825396Skarels #ifndef PORTSELECTOR 7925396Skarels #define ISPEED B9600 8025396Skarels #define IFLAGS (EVENP|ODDP|ECHO) 8125396Skarels #else 8225396Skarels #define ISPEED B4800 8325396Skarels #define IFLAGS (EVENP|ODDP) 8425396Skarels #endif 8525396Skarels 8625224Smckusick #ifndef lint 8725224Smckusick int ndmz = NDMZLINES; /* Used by pstat/iostat */ 8825224Smckusick #endif 8925224Smckusick 9025224Smckusick short dmzact[NDMZ]; /* Mask of active octets on the dmz */ 9125224Smckusick int dmzstart(); 9225224Smckusick 9325224Smckusick /* 9425224Smckusick * SILO_TIMEOUT represents the number of milliseconds characters can sit 9525224Smckusick * in the input silo without causing an interrupt. If data overruns or 9625224Smckusick * slow XON/XOFF occur, set it lower but AT LEAST equal to 1. 9725224Smckusick */ 9825224Smckusick #define SILO_TIMEOUT (3) 9925224Smckusick 10025224Smckusick /* 10125224Smckusick * DO_DMA_COUNT represents the threshold of the number of output 10225224Smckusick * characters beyond which the driver uses DMA mode. 10325224Smckusick */ 10425224Smckusick #define DO_DMA_COUNT (10) 10525224Smckusick 10625224Smckusick #define TRUE (1) 10725224Smckusick #define FALSE (0) 10825224Smckusick 10925435Skarels int cbase[NUBA]; /* base address in unibus map */ 11025224Smckusick int dmz_ubinfo[NUBA]; /* info about allocated unibus map */ 11125224Smckusick 11225224Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x) - (char *)cfree)) 11325224Smckusick 11425224Smckusick /* These flags are for debugging purposes only */ 11525224Smckusick int dmz_dma_on = 1; 11625224Smckusick 11725224Smckusick dmzprobe(reg) 11825224Smckusick caddr_t reg; 11925224Smckusick { 12025224Smckusick register int br, cvec; 12125224Smckusick register struct dmzdevice *dmz_addr; 12225224Smckusick register unsigned int a; 12325224Smckusick 12425224Smckusick dmz_addr = (struct dmzdevice *)reg; 12525224Smckusick 12625224Smckusick #ifdef lint 12725224Smckusick br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0); 12825224Smckusick dmzrinta(0); dmzrintb(0); dmzrintc(0); 12925224Smckusick #endif 13025224Smckusick 13125224Smckusick br = 0x15; 13225224Smckusick 13325224Smckusick a = dmz_addr->dmz_config; 13425224Smckusick if (((a>>12) & ~DMZ_INTERFACE) != 0) { 13525224Smckusick printf(" Unknown interface type\n"); 13625224Smckusick return (0); 13725224Smckusick } 13825224Smckusick if (((a>>8) & DMZ_NOC_MASK) != 3) { 13925224Smckusick printf(" Not all octets are available\n"); 14025224Smckusick return (0); 14125224Smckusick } 14225224Smckusick 14325224Smckusick cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6); 14425224Smckusick dmz_addr->dmz_config = cvec >> 2; 14525224Smckusick 14625224Smckusick return (sizeof(struct dmzdevice)); 14725224Smckusick } 14825224Smckusick 14925224Smckusick dmzattach(ui) 15025224Smckusick struct uba_device *ui; 15125224Smckusick { 15225224Smckusick dmzsoftCAR[ui->ui_unit] = ui->ui_flags; 15326218Skarels cbase[ui->ui_ubanum] = -1; 15425224Smckusick } 15525224Smckusick 15625224Smckusick /* ARGSUSED */ 15725224Smckusick dmzopen(device, flag) 15825224Smckusick dev_t device; 15925224Smckusick int flag; 16025224Smckusick { 16125224Smckusick register struct tty *tp; 16225224Smckusick register int unit, controller; 16325224Smckusick register struct dmzdevice *dmz_addr; 16425224Smckusick register struct uba_device *ui; 16525224Smckusick int priority; 16625224Smckusick int octet; 16725224Smckusick 16825224Smckusick unit = minor(device); 16925224Smckusick controller = DMZ(unit); 17025224Smckusick octet = OCTET(unit); 17125224Smckusick 17225224Smckusick if (unit >= NDMZLINES || 17325224Smckusick (ui = dmzinfo[controller]) == 0 || 17425224Smckusick ui->ui_alive == 0) 17525224Smckusick return (ENXIO); 17625224Smckusick 17725224Smckusick tp = &dmz_tty[unit]; 17825224Smckusick 17925224Smckusick if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0) 18025224Smckusick return (EBUSY); 18125224Smckusick 18225224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 18325224Smckusick tp->t_addr = (caddr_t)dmz_addr; 18425224Smckusick tp->t_oproc = dmzstart; 18525224Smckusick 18625224Smckusick /* 18725224Smckusick * Set up Unibus map registers. Block uba resets, which can 18825224Smckusick * clear the state. 18925224Smckusick */ 19025224Smckusick priority = spl5(); 19126218Skarels if (cbase[ui->ui_ubanum] == -1) { 19225224Smckusick dmz_ubinfo[ui->ui_ubanum] = 19325224Smckusick uballoc(ui->ui_ubanum, (caddr_t)cfree, 19425224Smckusick nclist * sizeof(struct cblock), 0); 19525224Smckusick if (dmz_ubinfo[ui->ui_ubanum] == 0) { 19625224Smckusick splx(priority); 19725224Smckusick printf("dmz: insufficient unibus map regs\n"); 19825435Skarels return (ENOMEM); 19925224Smckusick } 20026218Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(dmz_ubinfo[ui->ui_ubanum]); 20125224Smckusick } 20225224Smckusick 20325224Smckusick if ((dmzact[controller] & (1 << octet)) == 0) { 20425224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 20525224Smckusick dmzact[controller] |= 1 << octet; 20625224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 20725224Smckusick } 20825224Smckusick 20925224Smckusick splx(priority); 21025224Smckusick 21125224Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 21225224Smckusick ttychars(tp); 21325396Skarels tp->t_ispeed = tp->t_ospeed = ISPEED; 21425396Skarels tp->t_flags = IFLAGS; 21525224Smckusick dmz_softc[unit].dmz_state = 0; 21625224Smckusick } 21725655Skarels dmzparam(unit); 21825224Smckusick 21925224Smckusick /* 22025224Smckusick * Wait for carrier, then process line discipline specific open. 22125224Smckusick */ 22225655Skarels if ((dmzmctl(unit, DMZ_ON, DMSET) & DMZ_CAR) || 22325224Smckusick (dmzsoftCAR[controller] & (1 << (unit % 24)))) 22425224Smckusick tp->t_state |= TS_CARR_ON; 22525224Smckusick priority = spl5(); 22625224Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 22725224Smckusick tp->t_state |= TS_WOPEN; 22825224Smckusick sleep((caddr_t) &tp->t_rawq, TTIPRI); 22925224Smckusick } 23025224Smckusick splx(priority); 23125224Smckusick 23225435Skarels return ((*linesw[tp->t_line].l_open)(device, tp)); 23325224Smckusick } 23425224Smckusick 23525224Smckusick dmzparam(unit) 23625224Smckusick register int unit; 23725224Smckusick { 23825224Smckusick register struct tty *tp; 23925224Smckusick register struct dmzdevice *dmz_addr; 24025655Skarels register int line_parameters; 24125224Smckusick register int octet; 24225224Smckusick int priority; 24325224Smckusick 24425224Smckusick octet = OCTET(unit); 24525224Smckusick 24625224Smckusick tp = &dmz_tty[unit]; 24725224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 24825224Smckusick 24925224Smckusick priority = spl5(); 25025224Smckusick if ((tp->t_ispeed) == 0) { 25125224Smckusick tp->t_state |= TS_HUPCLS; 25225224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 25325224Smckusick splx(priority); 25425224Smckusick return; 25525224Smckusick } 25625224Smckusick 25725224Smckusick line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8); 25825224Smckusick 25925224Smckusick if ((tp->t_ispeed) == B134) 26025224Smckusick line_parameters |= DMZ_6BT | DMZ_PEN; 26125655Skarels else if (tp->t_flags & (RAW | LITOUT | PASS8)) 26225224Smckusick line_parameters |= DMZ_8BT; 26325224Smckusick else 26425224Smckusick line_parameters |= DMZ_7BT | DMZ_PEN; 26525224Smckusick 26625224Smckusick if (tp->t_flags & EVENP) 26725224Smckusick line_parameters |= DMZ_EPR; 26825224Smckusick if ((tp->t_ospeed) == B110) 26925224Smckusick line_parameters |= DMZ_SCD; 27025224Smckusick 27125224Smckusick line_parameters |= (unit & 07); 27225224Smckusick 27325224Smckusick dmz_addr->octet[octet].octet_lprm = line_parameters; 27425224Smckusick splx(priority); 27525224Smckusick } 27625224Smckusick 27725224Smckusick /* ARGSUSED */ 27825224Smckusick dmzclose(device, flag) 27925224Smckusick dev_t device; 28025224Smckusick int flag; 28125224Smckusick { 28225224Smckusick register struct tty *tp; 28325224Smckusick register int unit; 28425224Smckusick 28525224Smckusick unit = minor(device); 28625224Smckusick tp = &dmz_tty[unit]; 28725655Skarels (*linesw[tp->t_line].l_close)(tp); 28825224Smckusick 28925224Smckusick /* 29025655Skarels * Clear break, hang-up and close the modem. 29125224Smckusick */ 29225224Smckusick (void) dmzmctl(unit, DMZ_BRK, DMBIC); 29325224Smckusick if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 29425224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 29525224Smckusick ttyclose(tp); 29625224Smckusick return; 29725224Smckusick } 29825224Smckusick 29925224Smckusick dmzreset(uban) 30025224Smckusick int uban; 30125224Smckusick { 30225224Smckusick register int controller, unit; 30325224Smckusick register struct tty *tp; 30425224Smckusick register struct uba_device *ui; 30525224Smckusick register struct dmzdevice *dmz_addr; 30625224Smckusick int i; 30725224Smckusick int octet; 30825224Smckusick 30925224Smckusick for (controller = 0; controller < NDMZ; controller++) { 31025224Smckusick ui = dmzinfo[controller]; 31125224Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 31225224Smckusick continue; 31325224Smckusick printf("dmz%d ", controller); 31425224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 31525224Smckusick 31626218Skarels if (dmz_ubinfo[uban]) { 31725435Skarels dmz_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 31825435Skarels nclist * sizeof(struct cblock), 0); 31926218Skarels cbase[uban] = UBAI_ADDR(dmz_ubinfo[uban]); 32025435Skarels } 32125435Skarels 32225224Smckusick for (octet = 0; octet < 3; octet++) 32325224Smckusick if ((dmzact[controller] & (1 << octet)) != 0) { 32425224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 32525224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 32625224Smckusick } 32725224Smckusick 32825224Smckusick unit = controller * 24; 32925224Smckusick 33025224Smckusick /* 33125224Smckusick * If a unit is open or waiting for open to complete, 33225224Smckusick * reset it. 33325224Smckusick */ 33425224Smckusick for (i = 0; i < 24; i++) { 33525224Smckusick dmz_softc[unit].dmz_state = 0; 33625224Smckusick tp = &dmz_tty[unit]; 33725224Smckusick if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) { 33825224Smckusick dmzparam(unit); 33925224Smckusick (void) dmzmctl(unit, DMZ_ON, DMSET); 34025224Smckusick tp->t_state &= ~TS_BUSY; 34125224Smckusick dmzstart(tp); 34225224Smckusick } 34325224Smckusick unit++; 34425224Smckusick } 34525224Smckusick } 34625224Smckusick return; 34725224Smckusick } 34825224Smckusick 34925224Smckusick dmzread(device, uio) 35025224Smckusick dev_t device; 35125224Smckusick struct uio *uio; 35225224Smckusick { 35325224Smckusick register struct tty *tp; 35425224Smckusick int xstatus; 35525224Smckusick 35625224Smckusick tp = &dmz_tty[minor(device)]; 35725224Smckusick xstatus = (*linesw[tp->t_line].l_read)(tp, uio); 35825224Smckusick return (xstatus); 35925224Smckusick } 36025224Smckusick 36125224Smckusick dmzwrite(device, uio) 36225224Smckusick dev_t device; 36325224Smckusick struct uio *uio; 36425224Smckusick { 36525224Smckusick register struct tty *tp; 36625224Smckusick int xstatus; 36725224Smckusick 36825224Smckusick tp = &dmz_tty[minor(device)]; 36925224Smckusick xstatus = (*linesw[tp->t_line].l_write)(tp, uio); 37025224Smckusick return (xstatus); 37125224Smckusick } 37225224Smckusick 37325224Smckusick dmzrinta(controller) 37425224Smckusick int controller; 37525224Smckusick { 37625224Smckusick dmzrint(controller, 0); 37725224Smckusick } 37825224Smckusick 37925224Smckusick dmzrintb(controller) 38025224Smckusick int controller; 38125224Smckusick { 38225224Smckusick dmzrint(controller, 1); 38325224Smckusick } 38425224Smckusick 38525224Smckusick dmzrintc(controller) 38625224Smckusick int controller; 38725224Smckusick { 38825224Smckusick dmzrint(controller, 2); 38925224Smckusick } 39025224Smckusick 39125224Smckusick dmzrint(controller, octet) 39225224Smckusick int controller; 39325224Smckusick register int octet; 39425224Smckusick { 39525224Smckusick register struct tty *tp; 39625224Smckusick register int character; 39725224Smckusick register struct dmzdevice *dmz_addr; 39825224Smckusick register struct tty *tp0; 39925224Smckusick register int unit; 40025224Smckusick register struct uba_device *ui; 40125396Skarels int overrun; 40225224Smckusick 40325224Smckusick overrun = 0; 40425224Smckusick ui = dmzinfo[controller]; 40525224Smckusick if (ui == 0 || ui->ui_alive == 0) 40625224Smckusick return; 40725224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 40825224Smckusick tp0 = &dmz_tty[controller * 24]; 40925224Smckusick 41025224Smckusick while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) { 41125224Smckusick unit = (character >> 8) & 07; /* unit is bits 8-10 of rb */ 41225224Smckusick tp = tp0 + (octet * 8 + unit); 41325224Smckusick 41426218Skarels if (character & DMZ_DSC) { 41525655Skarels dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | unit; 41625655Skarels if (dmz_addr->octet[octet].octet_rmstsc & DMZ_CAR) 41725396Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 41826218Skarels else if (dmzsoftCAR[controller] & 41926218Skarels (1 << (octet * 8 + unit)) == 0 && 42026218Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 42125655Skarels (void)dmzmctl(tp - dmz_tty, DMZ_OFF, DMSET); 42225224Smckusick continue; 42325224Smckusick } 42425224Smckusick 42525396Skarels if ((tp->t_state&TS_ISOPEN)==0) { 42625396Skarels wakeup((caddr_t)&tp->t_rawq); 42725396Skarels #ifdef PORTSELECTOR 42825396Skarels if ((tp->t_state&TS_WOPEN) == 0) 42925396Skarels #endif 43025396Skarels continue; 43125224Smckusick } 43225224Smckusick 43325224Smckusick if (character & DMZ_PE) { 43425224Smckusick if ((tp->t_flags & (EVENP | ODDP)) == EVENP || 43525224Smckusick (tp->t_flags & (EVENP | ODDP)) == ODDP) 43625224Smckusick continue; 43725224Smckusick } 43825224Smckusick 43925224Smckusick if ((character & DMZ_DO) && overrun == 0) { 44025435Skarels log(LOG_WARNING, "dmz%d: silo overflow\n", controller); 44125224Smckusick overrun = 1; 44225224Smckusick } 44325224Smckusick 44425224Smckusick if (character & DMZ_FE) { 44525224Smckusick if (tp->t_flags & RAW) 44625224Smckusick character = 0; 44725224Smckusick else 44825224Smckusick character = tp->t_intrc; 44925224Smckusick } 45025224Smckusick 45125224Smckusick (*linesw[tp->t_line].l_rint)(character, tp); 45225224Smckusick } 45325224Smckusick 45425224Smckusick return; 45525224Smckusick } 45625224Smckusick 45725224Smckusick dmzxinta(controller) 45825224Smckusick int controller; 45925224Smckusick { 46025224Smckusick dmzxint(controller, 0); 46125224Smckusick } 46225224Smckusick 46325224Smckusick dmzxintb(controller) 46425224Smckusick int controller; 46525224Smckusick { 46625224Smckusick dmzxint(controller, 1); 46725224Smckusick } 46825224Smckusick 46925224Smckusick dmzxintc(controller) 47025224Smckusick int controller; 47125224Smckusick { 47225224Smckusick dmzxint(controller, 2); 47325224Smckusick } 47425224Smckusick 47525224Smckusick dmzxint(controller, octet) 47625224Smckusick int controller; 47725224Smckusick register int octet; 47825224Smckusick { 47925224Smckusick register struct tty *tp; 48025224Smckusick register struct dmzdevice *dmz_addr; 48125224Smckusick register struct uba_device *ui; 48225224Smckusick register int unit, t; 48325224Smckusick int priority; 48425224Smckusick 48525224Smckusick ui = dmzinfo[controller]; 48625224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 48725224Smckusick 48825224Smckusick priority = spl5(); 48925224Smckusick 49025224Smckusick while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) { 49125224Smckusick unit = controller * 24 + (octet * 8 + ((t>>8) & 07)); 49225224Smckusick tp = &dmz_tty[unit]; 49325224Smckusick tp->t_state &= ~TS_BUSY; 49425224Smckusick 49525224Smckusick if (t & DMZ_NXM) 49625224Smckusick printf("dmz%d: NXM line %d\n", controller, 49725224Smckusick octet * 8 + (unit & 07)); 49825224Smckusick 49925224Smckusick if (tp->t_state & TS_FLUSH) { 50025224Smckusick tp->t_state &= ~TS_FLUSH; 50125224Smckusick dmz_addr->octet[octet].octet_csr = 50225224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 50325224Smckusick dmz_addr->octet[octet].octet_lctmr = 50425224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 50525224Smckusick } else 50625224Smckusick if (dmz_softc[unit].dmz_state & ST_DMA) 50725224Smckusick ndflush(&tp->t_outq, dmz_softc[unit].dmz_count); 50825224Smckusick dmz_softc[unit].dmz_state = 0; 50925224Smckusick 51025224Smckusick if (tp->t_line) 51125224Smckusick (*linesw[tp->t_line].l_start)(tp); 51225224Smckusick else 51325224Smckusick dmzstart(tp); 51425224Smckusick } 51525224Smckusick 51625224Smckusick splx(priority); 51725224Smckusick return; 51825224Smckusick } 51925224Smckusick 52025224Smckusick dmzstart(tp) 52125224Smckusick register struct tty *tp; 52225224Smckusick { 52325224Smckusick register struct dmzdevice *dmz_addr; 52425224Smckusick register int unit, nch, room; 52525224Smckusick int controller, octet; 52625224Smckusick int priority, car, use_dma; 52725224Smckusick register int i; 52825224Smckusick register char *cp; 52925224Smckusick 53025224Smckusick unit = minor(tp->t_dev); 53125224Smckusick controller = DMZ(unit); 53225224Smckusick octet = OCTET(unit); 53325224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 53425224Smckusick 53525224Smckusick priority = spl5(); 53625224Smckusick 53725224Smckusick if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 53825224Smckusick goto out; 53925224Smckusick 54025224Smckusick /* 54125224Smckusick * If the transmitter has been disabled, reenable it. 54225224Smckusick * If the transmitter was disabled before the xint (the 54325224Smckusick * ST_INBUSY was still on), then reset the BUSY state and 54425224Smckusick * we will wait for the interrupt. If !TS_BUSY, we already 54525224Smckusick * saw the interrupt so we can start another transmission. 54625224Smckusick */ 54725224Smckusick if (dmz_softc[unit].dmz_state & ST_TXOFF) { 54825224Smckusick dmz_addr->octet[octet].octet_csr = 54925224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 55025224Smckusick dmz_addr->octet[octet].octet_lctmr = 55125224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 55225224Smckusick dmz_softc[unit].dmz_state &= ~ST_TXOFF; 55325224Smckusick if (dmz_softc[unit].dmz_state & ST_INBUSY) { 55425224Smckusick dmz_softc[unit].dmz_state &= ~ST_INBUSY; 55525224Smckusick tp->t_state |= TS_BUSY; 55625224Smckusick goto out; 55725224Smckusick } 55825224Smckusick } 55925224Smckusick 56025224Smckusick if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 56125224Smckusick if (tp->t_state & TS_ASLEEP) { 56225224Smckusick tp->t_state &= ~TS_ASLEEP; 56325224Smckusick wakeup((caddr_t)&tp->t_outq); 56425224Smckusick } 56525224Smckusick if (tp->t_wsel) { 56625224Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 56725224Smckusick tp->t_wsel = 0; 56825224Smckusick tp->t_state &= ~TS_WCOLL; 56925224Smckusick } 57025224Smckusick } 57125224Smckusick 57225224Smckusick if (tp->t_outq.c_cc == 0) 57325224Smckusick goto out; 57425655Skarels if (tp->t_flags & (RAW | LITOUT | PASS8)) 57525224Smckusick nch = ndqb(&tp->t_outq, 0); 57625224Smckusick else { 57725224Smckusick nch = ndqb(&tp->t_outq, 0200); 57825224Smckusick if (nch == 0) { 57925224Smckusick nch = getc(&tp->t_outq); 58025224Smckusick timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6); 58125224Smckusick tp->t_state |= TS_TIMEOUT; 58225224Smckusick goto out; 58325224Smckusick } 58425224Smckusick } 58525224Smckusick 58625224Smckusick /* 58725224Smckusick * Should we use DMA or SILO mode? 58825224Smckusick * If nch is greater than DO_DMA_COUNT then DMA. 58925224Smckusick */ 59025224Smckusick if (nch) { 59125224Smckusick dmz_addr->octet[octet].octet_csr = 59225224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 59325224Smckusick dmz_addr->octet[octet].octet_lctmr = 59425224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 59525224Smckusick tp->t_state |= TS_BUSY; 59625224Smckusick 59725224Smckusick use_dma = FALSE; 59825224Smckusick room = DMZ_SIZ; 59925224Smckusick 60025224Smckusick if (nch > DO_DMA_COUNT) 60125224Smckusick use_dma = TRUE; 60225224Smckusick 60325224Smckusick if (use_dma && dmz_dma_on) { 60425224Smckusick car = UBACVT(tp->t_outq.c_cf, 60525224Smckusick dmzinfo[controller]->ui_ubanum); 60625224Smckusick dmz_softc[unit].dmz_count = nch; 60725224Smckusick dmz_softc[unit].dmz_state |= ST_DMA; 60825224Smckusick dmz_addr->octet[octet].octet_csr = 60925224Smckusick DMZ_IE | IR_TBA | (unit & 07); 61025224Smckusick dmz_addr->octet[octet].octet_tba = car; 61125224Smckusick dmz_addr->octet[octet].octet_tcc = 61225224Smckusick ((car >> 2) & 0xc000) | nch; 61325224Smckusick } else { 61425224Smckusick dmz_softc[unit].dmz_state &= ~ST_DMA; 61525224Smckusick cp = tp->t_outq.c_cf; 61625224Smckusick nch = MIN(nch, room); 61725224Smckusick dmz_addr->octet[octet].octet_csr = 61825224Smckusick DMZ_IE | IR_TBUF | (unit & 07); 61925224Smckusick for (i = 0; i < nch; i++) 62025224Smckusick dmz_addr->octet[octet].octet_tbf = *cp++ ; 62125224Smckusick ndflush(&tp->t_outq, nch); 62225224Smckusick } 62325224Smckusick } 62425224Smckusick 62525224Smckusick out: 62625224Smckusick splx(priority); 62725224Smckusick return; 62825224Smckusick } 62925224Smckusick 63025224Smckusick /* ARGSUSED */ 63125224Smckusick dmzstop(tp, flag) 63225224Smckusick register struct tty *tp; 63325224Smckusick { 63425224Smckusick register struct dmzdevice *dmz_addr; 63525224Smckusick register int unit, priority, octet; 63625224Smckusick 63725224Smckusick priority = spl5(); 63825224Smckusick dmz_addr = (struct dmzdevice *) tp->t_addr; 63925224Smckusick unit = minor(tp->t_dev); 64025224Smckusick octet = OCTET(unit); 64125224Smckusick 64225224Smckusick dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE; 64325224Smckusick dmz_addr->octet[octet].octet_lctmr = 64425224Smckusick (dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE); 64525224Smckusick dmz_softc[unit].dmz_state |= ST_TXOFF; 64625224Smckusick if ((tp->t_state & TS_TTSTOP) == 0) { 64725224Smckusick tp->t_state |= (TS_FLUSH | TS_BUSY); 64825224Smckusick dmz_addr->octet[octet].octet_lctmr = 64925224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_FLS); 65025224Smckusick } else if (tp->t_state & TS_BUSY) { 65125224Smckusick dmz_softc[unit].dmz_state |= ST_INBUSY; 65225224Smckusick tp->t_state &= ~TS_BUSY; 65325224Smckusick } 65425224Smckusick 65525224Smckusick splx(priority); 65625224Smckusick return; 65725224Smckusick } 65825224Smckusick 65925224Smckusick /* ARGSUSED */ 66025224Smckusick dmzioctl(device, command, data, flag) 66125224Smckusick dev_t device; 66225224Smckusick caddr_t data; 66325224Smckusick { 66425224Smckusick register struct tty *tp; 66525224Smckusick register int unit; 66625224Smckusick int error; 66725224Smckusick 66825224Smckusick unit = minor(device); 66925224Smckusick tp = &dmz_tty[unit]; 67025224Smckusick 67125224Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag); 67225224Smckusick if (error >= 0) 67325224Smckusick return (error); 67425224Smckusick error = ttioctl(tp, command, data, flag); 67525224Smckusick if (error >= 0) { 67625655Skarels if (command == TIOCSETP || command == TIOCSETN || 67725655Skarels command == TIOCLSET || command == TIOCLBIS || 67825655Skarels command == TIOCLBIC) 67925224Smckusick dmzparam(unit); 68025224Smckusick return (error); 68125224Smckusick } 68225224Smckusick 68325224Smckusick switch (command) { 68425224Smckusick case TIOCSBRK: 68525655Skarels (void) dmzmctl(unit, DMZ_BRK, DMBIS); 68625224Smckusick break; 68725224Smckusick case TIOCCBRK: 68825655Skarels (void) dmzmctl(unit, DMZ_BRK, DMBIC); 68925224Smckusick break; 69025224Smckusick case TIOCSDTR: 69125655Skarels (void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIS); 69225224Smckusick break; 69325224Smckusick case TIOCCDTR: 69425655Skarels (void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIC); 69525224Smckusick break; 69625224Smckusick case TIOCMSET: 69725655Skarels (void) dmzmctl(unit, dmtodmz(*(int *)data), DMSET); 69825224Smckusick break; 69925224Smckusick case TIOCMBIS: 70025655Skarels (void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIS); 70125224Smckusick break; 70225224Smckusick case TIOCMBIC: 70325655Skarels (void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIC); 70425224Smckusick break; 70525224Smckusick case TIOCMGET: 70625655Skarels *(int *)data = dmzmctl(unit, 0, DMGET); 70725224Smckusick break; 70825224Smckusick default: 70925224Smckusick return (ENOTTY); 71025224Smckusick } 71125224Smckusick return (0); 71225224Smckusick } 71325224Smckusick 71425655Skarels dmzmctl(unit, bits, how) 71525655Skarels register int unit; 71625224Smckusick int bits, how; 71725224Smckusick { 71825224Smckusick register struct dmzdevice *dmz_addr; 71925655Skarels register int modem_status, line_control; 72025224Smckusick int priority; 72125224Smckusick int octet; 72225224Smckusick 72325224Smckusick octet = OCTET(unit); 72425655Skarels dmz_addr = (struct dmzdevice *) dmzinfo[DMZ(unit)]->ui_addr; 72525224Smckusick 72625224Smckusick priority = spl5(); 72725655Skarels dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | (unit & 07); 72825655Skarels modem_status = dmz_addr->octet[octet].octet_rmstsc & 0xff00; 72925224Smckusick 73025224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 73125655Skarels line_control = dmz_addr->octet[octet].octet_lctmr; 73225224Smckusick 73325224Smckusick 73425224Smckusick switch (how) { 73525224Smckusick case DMSET: 73625655Skarels line_control = bits; 73725224Smckusick break; 73825224Smckusick case DMBIS: 73925655Skarels line_control |= bits; 74025224Smckusick break; 74125224Smckusick case DMBIC: 74225655Skarels line_control &= ~bits; 74325224Smckusick break; 74425224Smckusick case DMGET: 74525224Smckusick (void) splx(priority); 74625655Skarels return (dmztodm(modem_status, line_control)); 74725224Smckusick } 74825224Smckusick 74925224Smckusick dmz_addr->octet[octet].octet_csr = 75025224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 75125655Skarels dmz_addr->octet[octet].octet_lctmr = line_control; 75225224Smckusick 75325655Skarels splx(priority); 75425224Smckusick return (modem_status); 75525224Smckusick } 75625224Smckusick 75725224Smckusick /* 75825655Skarels * Routine to convert modem status from dm to dmz lctmr format. 75925224Smckusick */ 76025224Smckusick dmtodmz(bits) 76125224Smckusick register int bits; 76225224Smckusick { 76325655Skarels register int lcr = DMZ_LCE; 76425224Smckusick 76525655Skarels if (bits & DML_DTR) 76625655Skarels lcr |= DMZ_DTR; 76725655Skarels if (bits & DML_RTS) 76825655Skarels lcr |= DMZ_RTS; 76925655Skarels if (bits & DML_ST) 77025655Skarels lcr |= DMF_ST; 77125655Skarels if (bits & DML_USR) 77225655Skarels lcr |= DMZ_USRW; 77325655Skarels return (lcr); 77425224Smckusick } 77525224Smckusick 77625224Smckusick /* 77725655Skarels * Routine to convert modem status from dmz receive modem status 77825655Skarels * and line control register to dm format. 77925655Skarels * If dmz user modem read bit set, set DML_USR. 78025224Smckusick */ 78125655Skarels dmztodm(rms, lcr) 78225655Skarels register int rms, lcr; 78325224Smckusick { 78425224Smckusick 78525655Skarels rms = ((rms & (DMZ_DSR|DMZ_RNG|DMZ_CAR|DMZ_CTS|DMF_SR)) >> 7) | 78625655Skarels ((rms & DMZ_USRR) >> 1) | DML_LE; 78725655Skarels if (lcr & DMZ_DTR) 78825655Skarels rms |= DML_DTR; 78925655Skarels if (lcr & DMF_ST) 79025655Skarels rms |= DML_ST; 79125655Skarels if (lcr & DMZ_RTS) 79225655Skarels rms |= DML_RTS; 79325655Skarels return (rms); 79425224Smckusick } 79525224Smckusick #endif 796