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*25435Skarels * @(#)dmz.c 6.3 (Berkeley) 11/08/85 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 * NOTE: The modem control routines have NOT been tested yet!!! 1625224Smckusick * 1725224Smckusick * 9-Aug-85 Mike Meyer (mwm) at ucb 1825224Smckusick * Mangled into shape for 4.3. 1925224Smckusick */ 2025224Smckusick 2125224Smckusick #include "dmz.h" 2225224Smckusick #if NDMZ > 0 2325224Smckusick 2425224Smckusick 2525224Smckusick #include "../machine/pte.h" 2625224Smckusick 2725224Smckusick 2825224Smckusick #include "bk.h" 2925224Smckusick #include "uba.h" 3025224Smckusick #include "param.h" 3125224Smckusick #include "conf.h" 3225224Smckusick #include "dir.h" 3325224Smckusick #include "user.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" 44*25435Skarels #include "syslog.h" 4525224Smckusick 4625224Smckusick #include "ubareg.h" 4725224Smckusick #include "ubavar.h" 4825224Smckusick #include "dmzreg.h" 4925224Smckusick 5025224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint(); 5125224Smckusick struct uba_device *dmzinfo[NDMZ]; 5225224Smckusick u_short dmzstd[] = {0, 0}; 5325224Smckusick struct uba_driver dmzdriver = { 5425224Smckusick dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo 5525224Smckusick }; 5625224Smckusick 5725224Smckusick #define NDMZLINES (NDMZ*24) 5825224Smckusick 5925224Smckusick int ttrstrt(); 6025224Smckusick struct tty dmz_tty[NDMZLINES]; 6125224Smckusick 6225224Smckusick int dmzsoftCAR[NDMZ]; 6325224Smckusick 6425224Smckusick struct { 6525224Smckusick char dmz_state; /* dmz state */ 6625224Smckusick int dmz_count; /* dmz dma count */ 6725224Smckusick } dmz_softc[NDMZ*24]; 6825224Smckusick 6925224Smckusick #define ST_TXOFF (0x01) /* transmission turned off (^S) */ 7025224Smckusick #define ST_DMA (0x02) /* dma inprogress */ 7125224Smckusick #define ST_INBUSY (0x04) /* stop transmission in busy */ 7225224Smckusick 7325224Smckusick char dmz_speeds[] = { 7425224Smckusick 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 7525224Smckusick }; 7625224Smckusick 7725396Skarels #ifndef PORTSELECTOR 7825396Skarels #define ISPEED B9600 7925396Skarels #define IFLAGS (EVENP|ODDP|ECHO) 8025396Skarels #else 8125396Skarels #define ISPEED B4800 8225396Skarels #define IFLAGS (EVENP|ODDP) 8325396Skarels #endif 8425396Skarels 8525224Smckusick #ifndef lint 8625224Smckusick int ndmz = NDMZLINES; /* Used by pstat/iostat */ 8725224Smckusick #endif 8825224Smckusick 8925224Smckusick short dmzact[NDMZ]; /* Mask of active octets on the dmz */ 9025224Smckusick int dmzstart(); 9125224Smckusick 9225224Smckusick /* 9325224Smckusick * SILO_TIMEOUT represents the number of milliseconds characters can sit 9425224Smckusick * in the input silo without causing an interrupt. If data overruns or 9525224Smckusick * slow XON/XOFF occur, set it lower but AT LEAST equal to 1. 9625224Smckusick */ 9725224Smckusick #define SILO_TIMEOUT (3) 9825224Smckusick 9925224Smckusick /* 10025224Smckusick * DO_DMA_COUNT represents the threshold of the number of output 10125224Smckusick * characters beyond which the driver uses DMA mode. 10225224Smckusick */ 10325224Smckusick #define DO_DMA_COUNT (10) 10425224Smckusick 10525224Smckusick #define TRUE (1) 10625224Smckusick #define FALSE (0) 10725224Smckusick 108*25435Skarels int cbase[NUBA]; /* base address in unibus map */ 10925224Smckusick int dmz_ubinfo[NUBA]; /* info about allocated unibus map */ 11025224Smckusick 11125224Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x) - (char *)cfree)) 11225224Smckusick 11325224Smckusick /* These flags are for debugging purposes only */ 11425224Smckusick int dmz_dma_on = 1; 11525224Smckusick int dmz_debug_level; 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; 15325224Smckusick return; 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 tp->t_state |= TS_WOPEN; 18625224Smckusick 18725224Smckusick /* 18825224Smckusick * Set up Unibus map registers. Block uba resets, which can 18925224Smckusick * clear the state. 19025224Smckusick */ 19125224Smckusick priority = spl5(); 192*25435Skarels if (cbase[ui->ui_ubanum] == 0) { 19325224Smckusick dmz_ubinfo[ui->ui_ubanum] = 19425224Smckusick uballoc(ui->ui_ubanum, (caddr_t)cfree, 19525224Smckusick nclist * sizeof(struct cblock), 0); 19625224Smckusick if (dmz_ubinfo[ui->ui_ubanum] == 0) { 19725224Smckusick splx(priority); 19825224Smckusick printf("dmz: insufficient unibus map regs\n"); 199*25435Skarels return (ENOMEM); 20025224Smckusick } 20125224Smckusick cbase[ui->ui_ubanum] = dmz_ubinfo[ui->ui_ubanum] & 0x3ffff; 20225224Smckusick } 20325224Smckusick 20425224Smckusick if ((dmzact[controller] & (1 << octet)) == 0) { 20525224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 20625224Smckusick dmzact[controller] |= 1 << octet; 20725224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 20825224Smckusick } 20925224Smckusick 21025224Smckusick splx(priority); 21125224Smckusick 21225224Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 21325224Smckusick ttychars(tp); 21425396Skarels tp->t_ispeed = tp->t_ospeed = ISPEED; 21525396Skarels tp->t_flags = IFLAGS; 21625224Smckusick dmzparam(unit); 21725224Smckusick dmz_softc[unit].dmz_state = 0; 21825224Smckusick } 21925224Smckusick 22025224Smckusick /* 22125224Smckusick * Wait for carrier, then process line discipline specific open. 22225224Smckusick */ 22325224Smckusick if ((dmzmctl(device, DMZ_ON, DMSET) & (DMZ_CAR << 8)) || 22425224Smckusick (dmzsoftCAR[controller] & (1 << (unit % 24)))) 22525224Smckusick tp->t_state |= TS_CARR_ON; 22625224Smckusick priority = spl5(); 22725224Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 22825224Smckusick tp->t_state |= TS_WOPEN; 22925224Smckusick sleep((caddr_t) &tp->t_rawq, TTIPRI); 23025224Smckusick } 23125224Smckusick splx(priority); 23225224Smckusick 233*25435Skarels return ((*linesw[tp->t_line].l_open)(device, tp)); 23425224Smckusick } 23525224Smckusick 23625224Smckusick dmzparam(unit) 23725224Smckusick register int unit; 23825224Smckusick { 23925224Smckusick register struct tty *tp; 24025224Smckusick register struct dmzdevice *dmz_addr; 24125224Smckusick register int line_parameters, line_control; 24225224Smckusick register int octet; 24325224Smckusick int priority; 24425224Smckusick 24525224Smckusick octet = OCTET(unit); 24625224Smckusick 24725224Smckusick tp = &dmz_tty[unit]; 24825224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 24925224Smckusick 25025224Smckusick priority = spl5(); 25125224Smckusick if ((tp->t_ispeed) == 0) { 25225224Smckusick tp->t_state |= TS_HUPCLS; 25325224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 25425224Smckusick splx(priority); 25525224Smckusick return; 25625224Smckusick } 25725224Smckusick 25825224Smckusick line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8); 25925224Smckusick line_control = DMZ_LCE; 26025224Smckusick 26125224Smckusick if ((tp->t_ispeed) == B134) 26225224Smckusick line_parameters |= DMZ_6BT | DMZ_PEN; 26325224Smckusick else if (tp->t_flags & (RAW | LITOUT)) 26425224Smckusick line_parameters |= DMZ_8BT; 26525224Smckusick else 26625224Smckusick line_parameters |= DMZ_7BT | DMZ_PEN; 26725224Smckusick 26825224Smckusick if (tp->t_flags & EVENP) 26925224Smckusick line_parameters |= DMZ_EPR; 27025224Smckusick if ((tp->t_ospeed) == B110) 27125224Smckusick line_parameters |= DMZ_SCD; 27225224Smckusick 27325224Smckusick line_parameters |= (unit & 07); 27425224Smckusick 27525224Smckusick dmz_addr->octet[octet].octet_lprm = line_parameters; 27625224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 27725224Smckusick dmz_addr->octet[octet].octet_lctmr = 27825224Smckusick (dmz_addr->octet[octet].octet_lctmr | (line_control & 0xff)); 27925224Smckusick 28025224Smckusick splx(priority); 28125224Smckusick return; 28225224Smckusick } 28325224Smckusick 28425224Smckusick /* ARGSUSED */ 28525224Smckusick dmzclose(device, flag) 28625224Smckusick dev_t device; 28725224Smckusick int flag; 28825224Smckusick { 28925224Smckusick register struct tty *tp; 29025224Smckusick register int unit; 29125224Smckusick 29225224Smckusick unit = minor(device); 29325224Smckusick tp = &dmz_tty[unit]; 29425224Smckusick 29525224Smckusick /* 29625224Smckusick * Break, hang-up and close the modem. 29725224Smckusick */ 29825224Smckusick (void) dmzmctl(unit, DMZ_BRK, DMBIC); 29925224Smckusick if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 30025224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 30125224Smckusick ttyclose(tp); 30225224Smckusick return; 30325224Smckusick } 30425224Smckusick 30525224Smckusick dmzreset(uban) 30625224Smckusick int uban; 30725224Smckusick { 30825224Smckusick register int controller, unit; 30925224Smckusick register struct tty *tp; 31025224Smckusick register struct uba_device *ui; 31125224Smckusick register struct dmzdevice *dmz_addr; 31225224Smckusick int i; 31325224Smckusick int octet; 31425224Smckusick 31525224Smckusick for (controller = 0; controller < NDMZ; controller++) { 31625224Smckusick ui = dmzinfo[controller]; 31725224Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 31825224Smckusick continue; 31925224Smckusick printf("dmz%d ", controller); 32025224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 32125224Smckusick 322*25435Skarels if (cbase[uban] == 0) { 323*25435Skarels dmz_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 324*25435Skarels nclist * sizeof(struct cblock), 0); 325*25435Skarels cbase[uban] = dmz_ubinfo[uban] & 0x3ffff; 326*25435Skarels } 327*25435Skarels 32825224Smckusick for (octet = 0; octet < 3; octet++) 32925224Smckusick if ((dmzact[controller] & (1 << octet)) != 0) { 33025224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 33125224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 33225224Smckusick } 33325224Smckusick 33425224Smckusick unit = controller * 24; 33525224Smckusick 33625224Smckusick /* 33725224Smckusick * If a unit is open or waiting for open to complete, 33825224Smckusick * reset it. 33925224Smckusick */ 34025224Smckusick for (i = 0; i < 24; i++) { 34125224Smckusick dmz_softc[unit].dmz_state = 0; 34225224Smckusick tp = &dmz_tty[unit]; 34325224Smckusick if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) { 34425224Smckusick dmzparam(unit); 34525224Smckusick (void) dmzmctl(unit, DMZ_ON, DMSET); 34625224Smckusick tp->t_state &= ~TS_BUSY; 34725224Smckusick dmzstart(tp); 34825224Smckusick } 34925224Smckusick unit++; 35025224Smckusick } 35125224Smckusick } 35225224Smckusick return; 35325224Smckusick } 35425224Smckusick 35525224Smckusick dmzread(device, uio) 35625224Smckusick dev_t device; 35725224Smckusick struct uio *uio; 35825224Smckusick { 35925224Smckusick register struct tty *tp; 36025224Smckusick int xstatus; 36125224Smckusick 36225224Smckusick tp = &dmz_tty[minor(device)]; 36325224Smckusick xstatus = (*linesw[tp->t_line].l_read)(tp, uio); 36425224Smckusick return (xstatus); 36525224Smckusick } 36625224Smckusick 36725224Smckusick dmzwrite(device, uio) 36825224Smckusick dev_t device; 36925224Smckusick struct uio *uio; 37025224Smckusick { 37125224Smckusick register struct tty *tp; 37225224Smckusick int xstatus; 37325224Smckusick 37425224Smckusick tp = &dmz_tty[minor(device)]; 37525224Smckusick xstatus = (*linesw[tp->t_line].l_write)(tp, uio); 37625224Smckusick return (xstatus); 37725224Smckusick } 37825224Smckusick 37925224Smckusick dmzrinta(controller) 38025224Smckusick int controller; 38125224Smckusick { 38225224Smckusick dmzrint(controller, 0); 38325224Smckusick } 38425224Smckusick 38525224Smckusick dmzrintb(controller) 38625224Smckusick int controller; 38725224Smckusick { 38825224Smckusick dmzrint(controller, 1); 38925224Smckusick } 39025224Smckusick 39125224Smckusick dmzrintc(controller) 39225224Smckusick int controller; 39325224Smckusick { 39425224Smckusick dmzrint(controller, 2); 39525224Smckusick } 39625224Smckusick 39725224Smckusick dmzrint(controller, octet) 39825224Smckusick int controller; 39925224Smckusick register int octet; 40025224Smckusick { 40125224Smckusick register struct tty *tp; 40225224Smckusick register int character; 40325224Smckusick register struct dmzdevice *dmz_addr; 40425224Smckusick register struct tty *tp0; 40525224Smckusick register int unit; 40625224Smckusick register struct uba_device *ui; 40725396Skarels int overrun; 40825224Smckusick 40925224Smckusick overrun = 0; 41025224Smckusick ui = dmzinfo[controller]; 41125224Smckusick if (ui == 0 || ui->ui_alive == 0) 41225224Smckusick return; 41325224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 41425224Smckusick tp0 = &dmz_tty[controller * 24]; 41525224Smckusick 41625224Smckusick while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) { 41725224Smckusick unit = (character >> 8) & 07; /* unit is bits 8-10 of rb */ 41825224Smckusick tp = tp0 + (octet * 8 + unit); 41925224Smckusick 42025396Skarels if (character & DMZ_DSC && 42125396Skarels (dmzsoftCAR[controller] & (1 << (octet * 8 + unit))) == 0) { 42225396Skarels dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | unit; 42325396Skarels if (dmz_addr->octet[octet].octet_rms & DMZ_CAR) 42425396Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 42525396Skarels else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 42625396Skarels dmz_addr->octet[octet].octet_csr = 42725396Skarels DMZ_IE | IR_LCTMR | unit; 42825396Skarels dmz_addr->octet[octet].octet_lctmr = 42925396Skarels dmz_addr->octet[octet].octet_lctmr & 43025396Skarels ((DMZ_OFF<<8) | 0xff); 43125224Smckusick } 43225224Smckusick continue; 43325224Smckusick } 43425224Smckusick 43525396Skarels if ((tp->t_state&TS_ISOPEN)==0) { 43625396Skarels wakeup((caddr_t)&tp->t_rawq); 43725396Skarels #ifdef PORTSELECTOR 43825396Skarels if ((tp->t_state&TS_WOPEN) == 0) 43925396Skarels #endif 44025396Skarels continue; 44125224Smckusick } 44225224Smckusick 44325224Smckusick if (character & DMZ_PE) { 44425224Smckusick if ((tp->t_flags & (EVENP | ODDP)) == EVENP || 44525224Smckusick (tp->t_flags & (EVENP | ODDP)) == ODDP) 44625224Smckusick continue; 44725224Smckusick } 44825224Smckusick 44925224Smckusick if ((character & DMZ_DO) && overrun == 0) { 450*25435Skarels log(LOG_WARNING, "dmz%d: silo overflow\n", controller); 45125224Smckusick overrun = 1; 45225224Smckusick } 45325224Smckusick 45425224Smckusick if (character & DMZ_FE) { 45525224Smckusick if (tp->t_flags & RAW) 45625224Smckusick character = 0; 45725224Smckusick else 45825224Smckusick character = tp->t_intrc; 45925224Smckusick } 46025224Smckusick 46125224Smckusick (*linesw[tp->t_line].l_rint)(character, tp); 46225224Smckusick } 46325224Smckusick 46425224Smckusick return; 46525224Smckusick } 46625224Smckusick 46725224Smckusick dmzxinta(controller) 46825224Smckusick int controller; 46925224Smckusick { 47025224Smckusick dmzxint(controller, 0); 47125224Smckusick } 47225224Smckusick 47325224Smckusick dmzxintb(controller) 47425224Smckusick int controller; 47525224Smckusick { 47625224Smckusick dmzxint(controller, 1); 47725224Smckusick } 47825224Smckusick 47925224Smckusick dmzxintc(controller) 48025224Smckusick int controller; 48125224Smckusick { 48225224Smckusick dmzxint(controller, 2); 48325224Smckusick } 48425224Smckusick 48525224Smckusick dmzxint(controller, octet) 48625224Smckusick int controller; 48725224Smckusick register int octet; 48825224Smckusick { 48925224Smckusick register struct tty *tp; 49025224Smckusick register struct dmzdevice *dmz_addr; 49125224Smckusick register struct uba_device *ui; 49225224Smckusick register int unit, t; 49325224Smckusick int priority; 49425224Smckusick 49525224Smckusick ui = dmzinfo[controller]; 49625224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 49725224Smckusick 49825224Smckusick priority = spl5(); 49925224Smckusick 50025224Smckusick while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) { 50125224Smckusick unit = controller * 24 + (octet * 8 + ((t>>8) & 07)); 50225224Smckusick tp = &dmz_tty[unit]; 50325224Smckusick tp->t_state &= ~TS_BUSY; 50425224Smckusick 50525224Smckusick if (t & DMZ_NXM) 50625224Smckusick printf("dmz%d: NXM line %d\n", controller, 50725224Smckusick octet * 8 + (unit & 07)); 50825224Smckusick 50925224Smckusick if (tp->t_state & TS_FLUSH) { 51025224Smckusick tp->t_state &= ~TS_FLUSH; 51125224Smckusick dmz_addr->octet[octet].octet_csr = 51225224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 51325224Smckusick dmz_addr->octet[octet].octet_lctmr = 51425224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 51525224Smckusick } else 51625224Smckusick if (dmz_softc[unit].dmz_state & ST_DMA) 51725224Smckusick ndflush(&tp->t_outq, dmz_softc[unit].dmz_count); 51825224Smckusick dmz_softc[unit].dmz_state = 0; 51925224Smckusick 52025224Smckusick if (tp->t_line) 52125224Smckusick (*linesw[tp->t_line].l_start)(tp); 52225224Smckusick else 52325224Smckusick dmzstart(tp); 52425224Smckusick } 52525224Smckusick 52625224Smckusick splx(priority); 52725224Smckusick return; 52825224Smckusick } 52925224Smckusick 53025224Smckusick dmzstart(tp) 53125224Smckusick register struct tty *tp; 53225224Smckusick { 53325224Smckusick register struct dmzdevice *dmz_addr; 53425224Smckusick register int unit, nch, room; 53525224Smckusick int controller, octet; 53625224Smckusick int priority, car, use_dma; 53725224Smckusick register int i; 53825224Smckusick register char *cp; 53925224Smckusick 54025224Smckusick unit = minor(tp->t_dev); 54125224Smckusick controller = DMZ(unit); 54225224Smckusick octet = OCTET(unit); 54325224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 54425224Smckusick 54525224Smckusick priority = spl5(); 54625224Smckusick 54725224Smckusick if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 54825224Smckusick goto out; 54925224Smckusick 55025224Smckusick /* 55125224Smckusick * If the transmitter has been disabled, reenable it. 55225224Smckusick * If the transmitter was disabled before the xint (the 55325224Smckusick * ST_INBUSY was still on), then reset the BUSY state and 55425224Smckusick * we will wait for the interrupt. If !TS_BUSY, we already 55525224Smckusick * saw the interrupt so we can start another transmission. 55625224Smckusick */ 55725224Smckusick if (dmz_softc[unit].dmz_state & ST_TXOFF) { 55825224Smckusick dmz_addr->octet[octet].octet_csr = 55925224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 56025224Smckusick dmz_addr->octet[octet].octet_lctmr = 56125224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 56225224Smckusick dmz_softc[unit].dmz_state &= ~ST_TXOFF; 56325224Smckusick if (dmz_softc[unit].dmz_state & ST_INBUSY) { 56425224Smckusick dmz_softc[unit].dmz_state &= ~ST_INBUSY; 56525224Smckusick tp->t_state |= TS_BUSY; 56625224Smckusick goto out; 56725224Smckusick } 56825224Smckusick } 56925224Smckusick 57025224Smckusick if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 57125224Smckusick if (tp->t_state & TS_ASLEEP) { 57225224Smckusick tp->t_state &= ~TS_ASLEEP; 57325224Smckusick wakeup((caddr_t)&tp->t_outq); 57425224Smckusick } 57525224Smckusick if (tp->t_wsel) { 57625224Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 57725224Smckusick tp->t_wsel = 0; 57825224Smckusick tp->t_state &= ~TS_WCOLL; 57925224Smckusick } 58025224Smckusick } 58125224Smckusick 58225224Smckusick if (tp->t_outq.c_cc == 0) 58325224Smckusick goto out; 58425224Smckusick if (tp->t_flags & (RAW | LITOUT)) 58525224Smckusick nch = ndqb(&tp->t_outq, 0); 58625224Smckusick else { 58725224Smckusick nch = ndqb(&tp->t_outq, 0200); 58825224Smckusick if (nch == 0) { 58925224Smckusick nch = getc(&tp->t_outq); 59025224Smckusick timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6); 59125224Smckusick tp->t_state |= TS_TIMEOUT; 59225224Smckusick goto out; 59325224Smckusick } 59425224Smckusick } 59525224Smckusick 59625224Smckusick /* 59725224Smckusick * Should we use DMA or SILO mode? 59825224Smckusick * If nch is greater than DO_DMA_COUNT then DMA. 59925224Smckusick */ 60025224Smckusick if (nch) { 60125224Smckusick dmz_addr->octet[octet].octet_csr = 60225224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 60325224Smckusick dmz_addr->octet[octet].octet_lctmr = 60425224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 60525224Smckusick tp->t_state |= TS_BUSY; 60625224Smckusick 60725224Smckusick use_dma = FALSE; 60825224Smckusick room = DMZ_SIZ; 60925224Smckusick 61025224Smckusick if (nch > DO_DMA_COUNT) 61125224Smckusick use_dma = TRUE; 61225224Smckusick 61325224Smckusick if (use_dma && dmz_dma_on) { 61425224Smckusick car = UBACVT(tp->t_outq.c_cf, 61525224Smckusick dmzinfo[controller]->ui_ubanum); 61625224Smckusick dmz_softc[unit].dmz_count = nch; 61725224Smckusick dmz_softc[unit].dmz_state |= ST_DMA; 61825224Smckusick dmz_addr->octet[octet].octet_csr = 61925224Smckusick DMZ_IE | IR_TBA | (unit & 07); 62025224Smckusick dmz_addr->octet[octet].octet_tba = car; 62125224Smckusick dmz_addr->octet[octet].octet_tcc = 62225224Smckusick ((car >> 2) & 0xc000) | nch; 62325224Smckusick } else { 62425224Smckusick dmz_softc[unit].dmz_state &= ~ST_DMA; 62525224Smckusick cp = tp->t_outq.c_cf; 62625224Smckusick nch = MIN(nch, room); 62725224Smckusick dmz_addr->octet[octet].octet_csr = 62825224Smckusick DMZ_IE | IR_TBUF | (unit & 07); 62925224Smckusick for (i = 0; i < nch; i++) 63025224Smckusick dmz_addr->octet[octet].octet_tbf = *cp++ ; 63125224Smckusick ndflush(&tp->t_outq, nch); 63225224Smckusick } 63325224Smckusick } 63425224Smckusick 63525224Smckusick out: 63625224Smckusick splx(priority); 63725224Smckusick return; 63825224Smckusick } 63925224Smckusick 64025224Smckusick /* ARGSUSED */ 64125224Smckusick dmzstop(tp, flag) 64225224Smckusick register struct tty *tp; 64325224Smckusick { 64425224Smckusick register struct dmzdevice *dmz_addr; 64525224Smckusick register int unit, priority, octet; 64625224Smckusick 64725224Smckusick priority = spl5(); 64825224Smckusick dmz_addr = (struct dmzdevice *) tp->t_addr; 64925224Smckusick unit = minor(tp->t_dev); 65025224Smckusick octet = OCTET(unit); 65125224Smckusick 65225224Smckusick dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE; 65325224Smckusick dmz_addr->octet[octet].octet_lctmr = 65425224Smckusick (dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE); 65525224Smckusick dmz_softc[unit].dmz_state |= ST_TXOFF; 65625224Smckusick if ((tp->t_state & TS_TTSTOP) == 0) { 65725224Smckusick tp->t_state |= (TS_FLUSH | TS_BUSY); 65825224Smckusick dmz_addr->octet[octet].octet_lctmr = 65925224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_FLS); 66025224Smckusick } else if (tp->t_state & TS_BUSY) { 66125224Smckusick dmz_softc[unit].dmz_state |= ST_INBUSY; 66225224Smckusick tp->t_state &= ~TS_BUSY; 66325224Smckusick } 66425224Smckusick 66525224Smckusick splx(priority); 66625224Smckusick return; 66725224Smckusick } 66825224Smckusick 66925224Smckusick /* ARGSUSED */ 67025224Smckusick dmzioctl(device, command, data, flag) 67125224Smckusick dev_t device; 67225224Smckusick caddr_t data; 67325224Smckusick { 67425224Smckusick register struct tty *tp; 67525224Smckusick register int unit; 67625224Smckusick int error; 67725224Smckusick 67825224Smckusick unit = minor(device); 67925224Smckusick tp = &dmz_tty[unit]; 68025224Smckusick 68125224Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag); 68225224Smckusick if (error >= 0) 68325224Smckusick return (error); 68425224Smckusick error = ttioctl(tp, command, data, flag); 68525224Smckusick if (error >= 0) { 68625224Smckusick if (command == TIOCSETP || command == TIOCSETN) 68725224Smckusick dmzparam(unit); 68825224Smckusick return (error); 68925224Smckusick } 69025224Smckusick 69125224Smckusick switch (command) { 69225224Smckusick case TIOCSBRK: 69325224Smckusick (void) dmzmctl(device, DMZ_BRK, DMBIS); 69425224Smckusick break; 69525224Smckusick case TIOCCBRK: 69625224Smckusick (void) dmzmctl(device, DMZ_BRK, DMBIC); 69725224Smckusick break; 69825224Smckusick case TIOCSDTR: 69925224Smckusick (void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIS); 70025224Smckusick break; 70125224Smckusick case TIOCCDTR: 70225224Smckusick (void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIC); 70325224Smckusick break; 70425224Smckusick case TIOCMSET: 70525224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMSET); 70625224Smckusick break; 70725224Smckusick case TIOCMBIS: 70825224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMBIS); 70925224Smckusick break; 71025224Smckusick case TIOCMBIC: 71125224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMBIC); 71225224Smckusick break; 71325224Smckusick case TIOCMGET: 71425224Smckusick *(int *)data = dmztodm(dmzmctl(device, 0, DMGET)); 71525224Smckusick break; 71625224Smckusick default: 71725224Smckusick return (ENOTTY); 71825224Smckusick } 71925224Smckusick return (0); 72025224Smckusick } 72125224Smckusick 72225224Smckusick dmzmctl(device, bits, how) 72325224Smckusick dev_t device; 72425224Smckusick int bits, how; 72525224Smckusick { 72625224Smckusick register struct dmzdevice *dmz_addr; 72725224Smckusick register int unit, modem_status, line_control; 72825224Smckusick register int temp; 72925224Smckusick int priority; 73025224Smckusick int octet; 73125224Smckusick 73225224Smckusick unit = minor(device); 73325224Smckusick octet = OCTET(unit); 73425224Smckusick dmz_addr = (struct dmzdevice *) dmz_tty[unit].t_addr; 73525224Smckusick 73625224Smckusick priority = spl5(); 73725224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | (unit & 07); 73825224Smckusick modem_status = dmz_addr->octet[octet].octet_rms << 8; 73925224Smckusick 74025224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 74125224Smckusick temp = dmz_addr->octet[octet].octet_lctmr; 74225224Smckusick modem_status |= ((temp>>8) & (0x1f)); 74325396Skarels line_control = (temp & (0x3f)); 74425224Smckusick 745*25435Skarels if (line_control & DMZ_RBK) 74625224Smckusick modem_status |= DMZ_BRK; 74725224Smckusick 74825224Smckusick switch (how) { 74925224Smckusick case DMSET: 75025224Smckusick modem_status = (modem_status & 0xff00) | bits; 75125224Smckusick break; 75225224Smckusick case DMBIS: 75325224Smckusick modem_status |= bits; 75425224Smckusick break; 75525224Smckusick case DMBIC: 75625224Smckusick modem_status &= ~bits; 75725224Smckusick break; 75825224Smckusick case DMGET: 75925224Smckusick (void) splx(priority); 76025224Smckusick return (modem_status); 76125224Smckusick } 76225224Smckusick 76325224Smckusick if (modem_status & DMZ_BRK) 76425224Smckusick line_control |= DMZ_RBK; 76525224Smckusick else 76625224Smckusick line_control &= ~DMZ_RBK; 76725224Smckusick modem_status &= ~DMZ_BRK; 76825224Smckusick 76925224Smckusick dmz_addr->octet[octet].octet_csr = 77025224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 77125224Smckusick dmz_addr->octet[octet].octet_lctmr = 77225224Smckusick ((modem_status & 0x1f) << 8) | (line_control & 0x3f); 77325224Smckusick 77425224Smckusick (void) splx(priority); 77525224Smckusick return (modem_status); 77625224Smckusick } 77725224Smckusick 77825224Smckusick /* 77925224Smckusick * Routine to convert modem status from dm to dmz format. 78025224Smckusick * Pull bits 1 & 3 through unchanged. If dm secondary transmit bit is set, 78125224Smckusick * and/or dm request to send bit is set, and/or dm user modem signal bit 78225224Smckusick * is set, set the corresponding dmz bits. 78325224Smckusick */ 78425224Smckusick dmtodmz(bits) 78525224Smckusick register int bits; 78625224Smckusick { 78725224Smckusick register int b; 78825224Smckusick 78925224Smckusick b = bits & 012; 79025224Smckusick if (bits & DM_ST) 79125224Smckusick b |= DMZ_RAT; 79225224Smckusick if (bits & DM_RTS) 79325224Smckusick b |= DMZ_RTS; 79425224Smckusick if (bits & DM_USR) 79525224Smckusick b |= DMZ_USW; 79625224Smckusick return (b); 79725224Smckusick } 79825224Smckusick 79925224Smckusick /* 80025224Smckusick * Routine to convert modem status from dmz to dm format. Pull bits 1 & 3 80125224Smckusick * through unchanged. Pull bits 11 - 15 through as bits 4 - 8 and set bit 80225224Smckusick * 0 to dm line enable. If dmz user modem signal bit set, and/or dmz 80325224Smckusick * request to send bit set, then set the corresponding dm bit also. 80425224Smckusick */ 80525224Smckusick dmztodm(bits) 80625224Smckusick register int bits; 80725224Smckusick { 80825224Smckusick register int b; 80925224Smckusick 81025224Smckusick b = (bits & 012) | ((bits >> 7) & 0760) | DM_LE; 81125224Smckusick if (bits & DMZ_USR) 81225224Smckusick b |= DM_USR; 81325224Smckusick if (bits & DMZ_RTS) 81425224Smckusick b |= DM_RTS; 81525224Smckusick return (b); 81625224Smckusick } 81725224Smckusick #endif 818