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*27051Skarels * @(#)dmz.c 6.7 (Berkeley) 04/12/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" 3326837Skarels #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); 213*27051Skarels #ifndef PORTSELECTOR 214*27051Skarels if (tp->t_ispeed == 0) { 215*27051Skarels #else 216*27051Skarels tp->t_state |= TS_HUPCLS; 217*27051Skarels #endif PORTSELECTOR 218*27051Skarels tp->t_ispeed = ISPEED; 219*27051Skarels tp->t_ospeed = ISPEED; 220*27051Skarels tp->t_flags = IFLAGS; 221*27051Skarels #ifndef PORTSELECTOR 222*27051Skarels } 223*27051Skarels #endif PORTSELECTOR 22425224Smckusick dmz_softc[unit].dmz_state = 0; 22525224Smckusick } 22625655Skarels dmzparam(unit); 22725224Smckusick 22825224Smckusick /* 22925224Smckusick * Wait for carrier, then process line discipline specific open. 23025224Smckusick */ 23125655Skarels if ((dmzmctl(unit, DMZ_ON, DMSET) & DMZ_CAR) || 23225224Smckusick (dmzsoftCAR[controller] & (1 << (unit % 24)))) 23325224Smckusick tp->t_state |= TS_CARR_ON; 23425224Smckusick priority = spl5(); 23525224Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 23625224Smckusick tp->t_state |= TS_WOPEN; 23725224Smckusick sleep((caddr_t) &tp->t_rawq, TTIPRI); 23825224Smckusick } 23925224Smckusick splx(priority); 24025224Smckusick 24125435Skarels return ((*linesw[tp->t_line].l_open)(device, tp)); 24225224Smckusick } 24325224Smckusick 24425224Smckusick dmzparam(unit) 24525224Smckusick register int unit; 24625224Smckusick { 24725224Smckusick register struct tty *tp; 24825224Smckusick register struct dmzdevice *dmz_addr; 24925655Skarels register int line_parameters; 25025224Smckusick register int octet; 25125224Smckusick int priority; 25225224Smckusick 25325224Smckusick octet = OCTET(unit); 25425224Smckusick 25525224Smckusick tp = &dmz_tty[unit]; 25625224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 25725224Smckusick 25825224Smckusick priority = spl5(); 25925224Smckusick if ((tp->t_ispeed) == 0) { 26025224Smckusick tp->t_state |= TS_HUPCLS; 26125224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 26225224Smckusick splx(priority); 26325224Smckusick return; 26425224Smckusick } 26525224Smckusick 26625224Smckusick line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8); 26725224Smckusick 26825224Smckusick if ((tp->t_ispeed) == B134) 26925224Smckusick line_parameters |= DMZ_6BT | DMZ_PEN; 27025655Skarels else if (tp->t_flags & (RAW | LITOUT | PASS8)) 27125224Smckusick line_parameters |= DMZ_8BT; 27225224Smckusick else 27325224Smckusick line_parameters |= DMZ_7BT | DMZ_PEN; 27425224Smckusick 27525224Smckusick if (tp->t_flags & EVENP) 27625224Smckusick line_parameters |= DMZ_EPR; 27725224Smckusick if ((tp->t_ospeed) == B110) 27825224Smckusick line_parameters |= DMZ_SCD; 27925224Smckusick 28025224Smckusick line_parameters |= (unit & 07); 28125224Smckusick 28225224Smckusick dmz_addr->octet[octet].octet_lprm = line_parameters; 28325224Smckusick splx(priority); 28425224Smckusick } 28525224Smckusick 28625224Smckusick /* ARGSUSED */ 28725224Smckusick dmzclose(device, flag) 28825224Smckusick dev_t device; 28925224Smckusick int flag; 29025224Smckusick { 29125224Smckusick register struct tty *tp; 29225224Smckusick register int unit; 29325224Smckusick 29425224Smckusick unit = minor(device); 29525224Smckusick tp = &dmz_tty[unit]; 29625655Skarels (*linesw[tp->t_line].l_close)(tp); 29725224Smckusick 29825224Smckusick /* 29925655Skarels * Clear break, hang-up and close the modem. 30025224Smckusick */ 30125224Smckusick (void) dmzmctl(unit, DMZ_BRK, DMBIC); 30225224Smckusick if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 30325224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 30425224Smckusick ttyclose(tp); 30525224Smckusick return; 30625224Smckusick } 30725224Smckusick 30825224Smckusick dmzreset(uban) 30925224Smckusick int uban; 31025224Smckusick { 31125224Smckusick register int controller, unit; 31225224Smckusick register struct tty *tp; 31325224Smckusick register struct uba_device *ui; 31425224Smckusick register struct dmzdevice *dmz_addr; 31525224Smckusick int i; 31625224Smckusick int octet; 31725224Smckusick 31825224Smckusick for (controller = 0; controller < NDMZ; controller++) { 31925224Smckusick ui = dmzinfo[controller]; 32025224Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 32125224Smckusick continue; 32225224Smckusick printf("dmz%d ", controller); 32325224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 32425224Smckusick 32526218Skarels if (dmz_ubinfo[uban]) { 32625435Skarels dmz_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 32725435Skarels nclist * sizeof(struct cblock), 0); 32826218Skarels cbase[uban] = UBAI_ADDR(dmz_ubinfo[uban]); 32925435Skarels } 33025435Skarels 33125224Smckusick for (octet = 0; octet < 3; octet++) 33225224Smckusick if ((dmzact[controller] & (1 << octet)) != 0) { 33325224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 33425224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 33525224Smckusick } 33625224Smckusick 33725224Smckusick unit = controller * 24; 33825224Smckusick 33925224Smckusick /* 34025224Smckusick * If a unit is open or waiting for open to complete, 34125224Smckusick * reset it. 34225224Smckusick */ 34325224Smckusick for (i = 0; i < 24; i++) { 34425224Smckusick dmz_softc[unit].dmz_state = 0; 34525224Smckusick tp = &dmz_tty[unit]; 34625224Smckusick if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) { 34725224Smckusick dmzparam(unit); 34825224Smckusick (void) dmzmctl(unit, DMZ_ON, DMSET); 34925224Smckusick tp->t_state &= ~TS_BUSY; 35025224Smckusick dmzstart(tp); 35125224Smckusick } 35225224Smckusick unit++; 35325224Smckusick } 35425224Smckusick } 35525224Smckusick return; 35625224Smckusick } 35725224Smckusick 35825224Smckusick dmzread(device, uio) 35925224Smckusick dev_t device; 36025224Smckusick struct uio *uio; 36125224Smckusick { 36225224Smckusick register struct tty *tp; 36325224Smckusick int xstatus; 36425224Smckusick 36525224Smckusick tp = &dmz_tty[minor(device)]; 36625224Smckusick xstatus = (*linesw[tp->t_line].l_read)(tp, uio); 36725224Smckusick return (xstatus); 36825224Smckusick } 36925224Smckusick 37025224Smckusick dmzwrite(device, uio) 37125224Smckusick dev_t device; 37225224Smckusick struct uio *uio; 37325224Smckusick { 37425224Smckusick register struct tty *tp; 37525224Smckusick int xstatus; 37625224Smckusick 37725224Smckusick tp = &dmz_tty[minor(device)]; 37825224Smckusick xstatus = (*linesw[tp->t_line].l_write)(tp, uio); 37925224Smckusick return (xstatus); 38025224Smckusick } 38125224Smckusick 38225224Smckusick dmzrinta(controller) 38325224Smckusick int controller; 38425224Smckusick { 38525224Smckusick dmzrint(controller, 0); 38625224Smckusick } 38725224Smckusick 38825224Smckusick dmzrintb(controller) 38925224Smckusick int controller; 39025224Smckusick { 39125224Smckusick dmzrint(controller, 1); 39225224Smckusick } 39325224Smckusick 39425224Smckusick dmzrintc(controller) 39525224Smckusick int controller; 39625224Smckusick { 39725224Smckusick dmzrint(controller, 2); 39825224Smckusick } 39925224Smckusick 40025224Smckusick dmzrint(controller, octet) 40125224Smckusick int controller; 40225224Smckusick register int octet; 40325224Smckusick { 40425224Smckusick register struct tty *tp; 40525224Smckusick register int character; 40625224Smckusick register struct dmzdevice *dmz_addr; 40725224Smckusick register struct tty *tp0; 40825224Smckusick register int unit; 40925224Smckusick register struct uba_device *ui; 41025396Skarels int overrun; 41125224Smckusick 41225224Smckusick overrun = 0; 41325224Smckusick ui = dmzinfo[controller]; 41425224Smckusick if (ui == 0 || ui->ui_alive == 0) 41525224Smckusick return; 41625224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 41725224Smckusick tp0 = &dmz_tty[controller * 24]; 41825224Smckusick 41925224Smckusick while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) { 42025224Smckusick unit = (character >> 8) & 07; /* unit is bits 8-10 of rb */ 42125224Smckusick tp = tp0 + (octet * 8 + unit); 42225224Smckusick 42326218Skarels if (character & DMZ_DSC) { 42425655Skarels dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | unit; 42525655Skarels if (dmz_addr->octet[octet].octet_rmstsc & DMZ_CAR) 42625396Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 427*27051Skarels else if ((dmzsoftCAR[controller] & 428*27051Skarels (1 << (octet * 8 + unit))) == 0 && 42926218Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 43025655Skarels (void)dmzmctl(tp - dmz_tty, DMZ_OFF, DMSET); 43125224Smckusick continue; 43225224Smckusick } 43325224Smckusick 43425396Skarels if ((tp->t_state&TS_ISOPEN)==0) { 43525396Skarels wakeup((caddr_t)&tp->t_rawq); 43625396Skarels #ifdef PORTSELECTOR 43725396Skarels if ((tp->t_state&TS_WOPEN) == 0) 43825396Skarels #endif 43925396Skarels continue; 44025224Smckusick } 44125224Smckusick 44225224Smckusick if (character & DMZ_PE) { 44325224Smckusick if ((tp->t_flags & (EVENP | ODDP)) == EVENP || 44425224Smckusick (tp->t_flags & (EVENP | ODDP)) == ODDP) 44525224Smckusick continue; 44625224Smckusick } 44725224Smckusick 44825224Smckusick if ((character & DMZ_DO) && overrun == 0) { 44925435Skarels log(LOG_WARNING, "dmz%d: silo overflow\n", controller); 45025224Smckusick overrun = 1; 45125224Smckusick } 45225224Smckusick 45325224Smckusick if (character & DMZ_FE) { 45425224Smckusick if (tp->t_flags & RAW) 45525224Smckusick character = 0; 45625224Smckusick else 45725224Smckusick character = tp->t_intrc; 45825224Smckusick } 45925224Smckusick 46025224Smckusick (*linesw[tp->t_line].l_rint)(character, tp); 46125224Smckusick } 46225224Smckusick 46325224Smckusick return; 46425224Smckusick } 46525224Smckusick 46625224Smckusick dmzxinta(controller) 46725224Smckusick int controller; 46825224Smckusick { 46925224Smckusick dmzxint(controller, 0); 47025224Smckusick } 47125224Smckusick 47225224Smckusick dmzxintb(controller) 47325224Smckusick int controller; 47425224Smckusick { 47525224Smckusick dmzxint(controller, 1); 47625224Smckusick } 47725224Smckusick 47825224Smckusick dmzxintc(controller) 47925224Smckusick int controller; 48025224Smckusick { 48125224Smckusick dmzxint(controller, 2); 48225224Smckusick } 48325224Smckusick 48425224Smckusick dmzxint(controller, octet) 48525224Smckusick int controller; 48625224Smckusick register int octet; 48725224Smckusick { 48825224Smckusick register struct tty *tp; 48925224Smckusick register struct dmzdevice *dmz_addr; 49025224Smckusick register struct uba_device *ui; 49125224Smckusick register int unit, t; 49225224Smckusick int priority; 49325224Smckusick 49425224Smckusick ui = dmzinfo[controller]; 49525224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 49625224Smckusick 49725224Smckusick priority = spl5(); 49825224Smckusick 49925224Smckusick while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) { 50025224Smckusick unit = controller * 24 + (octet * 8 + ((t>>8) & 07)); 50125224Smckusick tp = &dmz_tty[unit]; 50225224Smckusick tp->t_state &= ~TS_BUSY; 50325224Smckusick 50425224Smckusick if (t & DMZ_NXM) 50525224Smckusick printf("dmz%d: NXM line %d\n", controller, 50625224Smckusick octet * 8 + (unit & 07)); 50725224Smckusick 50825224Smckusick if (tp->t_state & TS_FLUSH) { 50925224Smckusick tp->t_state &= ~TS_FLUSH; 51025224Smckusick dmz_addr->octet[octet].octet_csr = 51125224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 51225224Smckusick dmz_addr->octet[octet].octet_lctmr = 51325224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 51425224Smckusick } else 51525224Smckusick if (dmz_softc[unit].dmz_state & ST_DMA) 51625224Smckusick ndflush(&tp->t_outq, dmz_softc[unit].dmz_count); 51725224Smckusick dmz_softc[unit].dmz_state = 0; 51825224Smckusick 51925224Smckusick if (tp->t_line) 52025224Smckusick (*linesw[tp->t_line].l_start)(tp); 52125224Smckusick else 52225224Smckusick dmzstart(tp); 52325224Smckusick } 52425224Smckusick 52525224Smckusick splx(priority); 52625224Smckusick return; 52725224Smckusick } 52825224Smckusick 52925224Smckusick dmzstart(tp) 53025224Smckusick register struct tty *tp; 53125224Smckusick { 53225224Smckusick register struct dmzdevice *dmz_addr; 53325224Smckusick register int unit, nch, room; 53425224Smckusick int controller, octet; 53525224Smckusick int priority, car, use_dma; 53625224Smckusick register int i; 53725224Smckusick register char *cp; 53825224Smckusick 53925224Smckusick unit = minor(tp->t_dev); 54025224Smckusick controller = DMZ(unit); 54125224Smckusick octet = OCTET(unit); 54225224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 54325224Smckusick 54425224Smckusick priority = spl5(); 54525224Smckusick 54625224Smckusick if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 54725224Smckusick goto out; 54825224Smckusick 54925224Smckusick /* 55025224Smckusick * If the transmitter has been disabled, reenable it. 55125224Smckusick * If the transmitter was disabled before the xint (the 55225224Smckusick * ST_INBUSY was still on), then reset the BUSY state and 55325224Smckusick * we will wait for the interrupt. If !TS_BUSY, we already 55425224Smckusick * saw the interrupt so we can start another transmission. 55525224Smckusick */ 55625224Smckusick if (dmz_softc[unit].dmz_state & ST_TXOFF) { 55725224Smckusick dmz_addr->octet[octet].octet_csr = 55825224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 55925224Smckusick dmz_addr->octet[octet].octet_lctmr = 56025224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 56125224Smckusick dmz_softc[unit].dmz_state &= ~ST_TXOFF; 56225224Smckusick if (dmz_softc[unit].dmz_state & ST_INBUSY) { 56325224Smckusick dmz_softc[unit].dmz_state &= ~ST_INBUSY; 56425224Smckusick tp->t_state |= TS_BUSY; 56525224Smckusick goto out; 56625224Smckusick } 56725224Smckusick } 56825224Smckusick 56925224Smckusick if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 57025224Smckusick if (tp->t_state & TS_ASLEEP) { 57125224Smckusick tp->t_state &= ~TS_ASLEEP; 57225224Smckusick wakeup((caddr_t)&tp->t_outq); 57325224Smckusick } 57425224Smckusick if (tp->t_wsel) { 57525224Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 57625224Smckusick tp->t_wsel = 0; 57725224Smckusick tp->t_state &= ~TS_WCOLL; 57825224Smckusick } 57925224Smckusick } 58025224Smckusick 58125224Smckusick if (tp->t_outq.c_cc == 0) 58225224Smckusick goto out; 58325655Skarels if (tp->t_flags & (RAW | LITOUT | PASS8)) 58425224Smckusick nch = ndqb(&tp->t_outq, 0); 58525224Smckusick else { 58625224Smckusick nch = ndqb(&tp->t_outq, 0200); 58725224Smckusick if (nch == 0) { 58825224Smckusick nch = getc(&tp->t_outq); 58925224Smckusick timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6); 59025224Smckusick tp->t_state |= TS_TIMEOUT; 59125224Smckusick goto out; 59225224Smckusick } 59325224Smckusick } 59425224Smckusick 59525224Smckusick /* 59625224Smckusick * Should we use DMA or SILO mode? 59725224Smckusick * If nch is greater than DO_DMA_COUNT then DMA. 59825224Smckusick */ 59925224Smckusick if (nch) { 60025224Smckusick dmz_addr->octet[octet].octet_csr = 60125224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 60225224Smckusick dmz_addr->octet[octet].octet_lctmr = 60325224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 60425224Smckusick tp->t_state |= TS_BUSY; 60525224Smckusick 60625224Smckusick use_dma = FALSE; 60725224Smckusick room = DMZ_SIZ; 60825224Smckusick 60925224Smckusick if (nch > DO_DMA_COUNT) 61025224Smckusick use_dma = TRUE; 61125224Smckusick 61225224Smckusick if (use_dma && dmz_dma_on) { 61325224Smckusick car = UBACVT(tp->t_outq.c_cf, 61425224Smckusick dmzinfo[controller]->ui_ubanum); 61525224Smckusick dmz_softc[unit].dmz_count = nch; 61625224Smckusick dmz_softc[unit].dmz_state |= ST_DMA; 61725224Smckusick dmz_addr->octet[octet].octet_csr = 61825224Smckusick DMZ_IE | IR_TBA | (unit & 07); 61925224Smckusick dmz_addr->octet[octet].octet_tba = car; 62025224Smckusick dmz_addr->octet[octet].octet_tcc = 62125224Smckusick ((car >> 2) & 0xc000) | nch; 62225224Smckusick } else { 62325224Smckusick dmz_softc[unit].dmz_state &= ~ST_DMA; 62425224Smckusick cp = tp->t_outq.c_cf; 62525224Smckusick nch = MIN(nch, room); 62625224Smckusick dmz_addr->octet[octet].octet_csr = 62725224Smckusick DMZ_IE | IR_TBUF | (unit & 07); 62825224Smckusick for (i = 0; i < nch; i++) 62925224Smckusick dmz_addr->octet[octet].octet_tbf = *cp++ ; 63025224Smckusick ndflush(&tp->t_outq, nch); 63125224Smckusick } 63225224Smckusick } 63325224Smckusick 63425224Smckusick out: 63525224Smckusick splx(priority); 63625224Smckusick return; 63725224Smckusick } 63825224Smckusick 63925224Smckusick /* ARGSUSED */ 64025224Smckusick dmzstop(tp, flag) 64125224Smckusick register struct tty *tp; 64225224Smckusick { 64325224Smckusick register struct dmzdevice *dmz_addr; 64425224Smckusick register int unit, priority, octet; 64525224Smckusick 64625224Smckusick priority = spl5(); 64725224Smckusick dmz_addr = (struct dmzdevice *) tp->t_addr; 64825224Smckusick unit = minor(tp->t_dev); 64925224Smckusick octet = OCTET(unit); 65025224Smckusick 65125224Smckusick dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE; 65225224Smckusick dmz_addr->octet[octet].octet_lctmr = 65325224Smckusick (dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE); 65425224Smckusick dmz_softc[unit].dmz_state |= ST_TXOFF; 65525224Smckusick if ((tp->t_state & TS_TTSTOP) == 0) { 65625224Smckusick tp->t_state |= (TS_FLUSH | TS_BUSY); 65725224Smckusick dmz_addr->octet[octet].octet_lctmr = 65825224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_FLS); 65925224Smckusick } else if (tp->t_state & TS_BUSY) { 66025224Smckusick dmz_softc[unit].dmz_state |= ST_INBUSY; 66125224Smckusick tp->t_state &= ~TS_BUSY; 66225224Smckusick } 66325224Smckusick 66425224Smckusick splx(priority); 66525224Smckusick return; 66625224Smckusick } 66725224Smckusick 66825224Smckusick /* ARGSUSED */ 66925224Smckusick dmzioctl(device, command, data, flag) 67025224Smckusick dev_t device; 67125224Smckusick caddr_t data; 67225224Smckusick { 67325224Smckusick register struct tty *tp; 67425224Smckusick register int unit; 67525224Smckusick int error; 67625224Smckusick 67725224Smckusick unit = minor(device); 67825224Smckusick tp = &dmz_tty[unit]; 67925224Smckusick 68025224Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag); 68125224Smckusick if (error >= 0) 68225224Smckusick return (error); 68325224Smckusick error = ttioctl(tp, command, data, flag); 68425224Smckusick if (error >= 0) { 68525655Skarels if (command == TIOCSETP || command == TIOCSETN || 68625655Skarels command == TIOCLSET || command == TIOCLBIS || 68725655Skarels command == TIOCLBIC) 68825224Smckusick dmzparam(unit); 68925224Smckusick return (error); 69025224Smckusick } 69125224Smckusick 69225224Smckusick switch (command) { 69325224Smckusick case TIOCSBRK: 69425655Skarels (void) dmzmctl(unit, DMZ_BRK, DMBIS); 69525224Smckusick break; 69625224Smckusick case TIOCCBRK: 69725655Skarels (void) dmzmctl(unit, DMZ_BRK, DMBIC); 69825224Smckusick break; 69925224Smckusick case TIOCSDTR: 70025655Skarels (void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIS); 70125224Smckusick break; 70225224Smckusick case TIOCCDTR: 70325655Skarels (void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIC); 70425224Smckusick break; 70525224Smckusick case TIOCMSET: 70625655Skarels (void) dmzmctl(unit, dmtodmz(*(int *)data), DMSET); 70725224Smckusick break; 70825224Smckusick case TIOCMBIS: 70925655Skarels (void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIS); 71025224Smckusick break; 71125224Smckusick case TIOCMBIC: 71225655Skarels (void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIC); 71325224Smckusick break; 71425224Smckusick case TIOCMGET: 71525655Skarels *(int *)data = dmzmctl(unit, 0, DMGET); 71625224Smckusick break; 71725224Smckusick default: 71825224Smckusick return (ENOTTY); 71925224Smckusick } 72025224Smckusick return (0); 72125224Smckusick } 72225224Smckusick 72325655Skarels dmzmctl(unit, bits, how) 72425655Skarels register int unit; 72525224Smckusick int bits, how; 72625224Smckusick { 72725224Smckusick register struct dmzdevice *dmz_addr; 72825655Skarels register int modem_status, line_control; 72925224Smckusick int priority; 73025224Smckusick int octet; 73125224Smckusick 73225224Smckusick octet = OCTET(unit); 73325655Skarels dmz_addr = (struct dmzdevice *) dmzinfo[DMZ(unit)]->ui_addr; 73425224Smckusick 73525224Smckusick priority = spl5(); 73625655Skarels dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | (unit & 07); 73725655Skarels modem_status = dmz_addr->octet[octet].octet_rmstsc & 0xff00; 73825224Smckusick 73925224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 74025655Skarels line_control = dmz_addr->octet[octet].octet_lctmr; 74125224Smckusick 74225224Smckusick 74325224Smckusick switch (how) { 74425224Smckusick case DMSET: 74525655Skarels line_control = bits; 74625224Smckusick break; 74725224Smckusick case DMBIS: 74825655Skarels line_control |= bits; 74925224Smckusick break; 75025224Smckusick case DMBIC: 75125655Skarels line_control &= ~bits; 75225224Smckusick break; 75325224Smckusick case DMGET: 75425224Smckusick (void) splx(priority); 75525655Skarels return (dmztodm(modem_status, line_control)); 75625224Smckusick } 75725224Smckusick 75825224Smckusick dmz_addr->octet[octet].octet_csr = 75925224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 76025655Skarels dmz_addr->octet[octet].octet_lctmr = line_control; 76125224Smckusick 76225655Skarels splx(priority); 76325224Smckusick return (modem_status); 76425224Smckusick } 76525224Smckusick 76625224Smckusick /* 76725655Skarels * Routine to convert modem status from dm to dmz lctmr format. 76825224Smckusick */ 76925224Smckusick dmtodmz(bits) 77025224Smckusick register int bits; 77125224Smckusick { 77225655Skarels register int lcr = DMZ_LCE; 77325224Smckusick 77425655Skarels if (bits & DML_DTR) 77525655Skarels lcr |= DMZ_DTR; 77625655Skarels if (bits & DML_RTS) 77725655Skarels lcr |= DMZ_RTS; 77825655Skarels if (bits & DML_ST) 77925655Skarels lcr |= DMF_ST; 78025655Skarels if (bits & DML_USR) 78125655Skarels lcr |= DMZ_USRW; 78225655Skarels return (lcr); 78325224Smckusick } 78425224Smckusick 78525224Smckusick /* 78625655Skarels * Routine to convert modem status from dmz receive modem status 78725655Skarels * and line control register to dm format. 78825655Skarels * If dmz user modem read bit set, set DML_USR. 78925224Smckusick */ 79025655Skarels dmztodm(rms, lcr) 79125655Skarels register int rms, lcr; 79225224Smckusick { 79325224Smckusick 79425655Skarels rms = ((rms & (DMZ_DSR|DMZ_RNG|DMZ_CAR|DMZ_CTS|DMF_SR)) >> 7) | 79525655Skarels ((rms & DMZ_USRR) >> 1) | DML_LE; 79625655Skarels if (lcr & DMZ_DTR) 79725655Skarels rms |= DML_DTR; 79825655Skarels if (lcr & DMF_ST) 79925655Skarels rms |= DML_ST; 80025655Skarels if (lcr & DMZ_RTS) 80125655Skarels rms |= DML_RTS; 80225655Skarels return (rms); 80325224Smckusick } 80425224Smckusick #endif 805