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*25396Skarels * @(#)dmz.c 6.2 (Berkeley) 11/04/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" 4425224Smckusick 4525224Smckusick #include "ubareg.h" 4625224Smckusick #include "ubavar.h" 4725224Smckusick #include "dmzreg.h" 4825224Smckusick 4925224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint(); 5025224Smckusick struct uba_device *dmzinfo[NDMZ]; 5125224Smckusick u_short dmzstd[] = {0, 0}; 5225224Smckusick struct uba_driver dmzdriver = { 5325224Smckusick dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo 5425224Smckusick }; 5525224Smckusick 5625224Smckusick #define NDMZLINES (NDMZ*24) 5725224Smckusick 5825224Smckusick int ttrstrt(); 5925224Smckusick struct tty dmz_tty[NDMZLINES]; 6025224Smckusick 6125224Smckusick int dmzsoftCAR[NDMZ]; 6225224Smckusick 6325224Smckusick struct { 6425224Smckusick char dmz_state; /* dmz state */ 6525224Smckusick int dmz_count; /* dmz dma count */ 6625224Smckusick } dmz_softc[NDMZ*24]; 6725224Smckusick 6825224Smckusick #define ST_TXOFF (0x01) /* transmission turned off (^S) */ 6925224Smckusick #define ST_DMA (0x02) /* dma inprogress */ 7025224Smckusick #define ST_INBUSY (0x04) /* stop transmission in busy */ 7125224Smckusick 7225224Smckusick char dmz_speeds[] = { 7325224Smckusick 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 7425224Smckusick }; 7525224Smckusick 76*25396Skarels #ifndef PORTSELECTOR 77*25396Skarels #define ISPEED B9600 78*25396Skarels #define IFLAGS (EVENP|ODDP|ECHO) 79*25396Skarels #else 80*25396Skarels #define ISPEED B4800 81*25396Skarels #define IFLAGS (EVENP|ODDP) 82*25396Skarels #endif 83*25396Skarels 8425224Smckusick #ifndef lint 8525224Smckusick int ndmz = NDMZLINES; /* Used by pstat/iostat */ 8625224Smckusick #endif 8725224Smckusick 8825224Smckusick short dmzact[NDMZ]; /* Mask of active octets on the dmz */ 8925224Smckusick int dmzstart(); 9025224Smckusick 9125224Smckusick /* 9225224Smckusick * SILO_TIMEOUT represents the number of milliseconds characters can sit 9325224Smckusick * in the input silo without causing an interrupt. If data overruns or 9425224Smckusick * slow XON/XOFF occur, set it lower but AT LEAST equal to 1. 9525224Smckusick */ 9625224Smckusick #define SILO_TIMEOUT (3) 9725224Smckusick 9825224Smckusick /* 9925224Smckusick * DO_DMA_COUNT represents the threshold of the number of output 10025224Smckusick * characters beyond which the driver uses DMA mode. 10125224Smckusick */ 10225224Smckusick #define DO_DMA_COUNT (10) 10325224Smckusick 10425224Smckusick #define TRUE (1) 10525224Smckusick #define FALSE (0) 10625224Smckusick 10725224Smckusick static int cbase[NUBA]; /* base address in unibus map */ 10825224Smckusick int dmz_ubinfo[NUBA]; /* info about allocated unibus map */ 10925224Smckusick 11025224Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x) - (char *)cfree)) 11125224Smckusick 11225224Smckusick /* These flags are for debugging purposes only */ 11325224Smckusick int dmz_dma_on = 1; 11425224Smckusick int dmz_debug_level; 11525224Smckusick 11625224Smckusick dmzprobe(reg) 11725224Smckusick caddr_t reg; 11825224Smckusick { 11925224Smckusick register int br, cvec; 12025224Smckusick register struct dmzdevice *dmz_addr; 12125224Smckusick register unsigned int a; 12225224Smckusick 12325224Smckusick dmz_addr = (struct dmzdevice *)reg; 12425224Smckusick 12525224Smckusick #ifdef lint 12625224Smckusick br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0); 12725224Smckusick dmzrinta(0); dmzrintb(0); dmzrintc(0); 12825224Smckusick #endif 12925224Smckusick 13025224Smckusick br = 0x15; 13125224Smckusick 13225224Smckusick a = dmz_addr->dmz_config; 13325224Smckusick if (((a>>12) & ~DMZ_INTERFACE) != 0) { 13425224Smckusick printf(" Unknown interface type\n"); 13525224Smckusick return (0); 13625224Smckusick } 13725224Smckusick if (((a>>8) & DMZ_NOC_MASK) != 3) { 13825224Smckusick printf(" Not all octets are available\n"); 13925224Smckusick return (0); 14025224Smckusick } 14125224Smckusick 14225224Smckusick cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6); 14325224Smckusick dmz_addr->dmz_config = cvec >> 2; 14425224Smckusick 14525224Smckusick return (sizeof(struct dmzdevice)); 14625224Smckusick } 14725224Smckusick 14825224Smckusick dmzattach(ui) 14925224Smckusick struct uba_device *ui; 15025224Smckusick { 15125224Smckusick dmzsoftCAR[ui->ui_unit] = ui->ui_flags; 15225224Smckusick return; 15325224Smckusick } 15425224Smckusick 15525224Smckusick /* ARGSUSED */ 15625224Smckusick dmzopen(device, flag) 15725224Smckusick dev_t device; 15825224Smckusick int flag; 15925224Smckusick { 16025224Smckusick register struct tty *tp; 16125224Smckusick register int unit, controller; 16225224Smckusick register struct dmzdevice *dmz_addr; 16325224Smckusick register struct uba_device *ui; 16425224Smckusick int priority; 16525224Smckusick int xstatus; 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(); 19225224Smckusick if (dmz_ubinfo[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"); 19925224Smckusick return (-1); /* Is this the right thing to return? */ 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); 214*25396Skarels tp->t_ispeed = tp->t_ospeed = ISPEED; 215*25396Skarels 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 23325224Smckusick xstatus = (*linesw[tp->t_line].l_open)(device, tp); 23425224Smckusick return (xstatus); 23525224Smckusick } 23625224Smckusick 23725224Smckusick dmzparam(unit) 23825224Smckusick register int unit; 23925224Smckusick { 24025224Smckusick register struct tty *tp; 24125224Smckusick register struct dmzdevice *dmz_addr; 24225224Smckusick register int line_parameters, line_control; 24325224Smckusick register int octet; 24425224Smckusick int priority; 24525224Smckusick 24625224Smckusick octet = OCTET(unit); 24725224Smckusick 24825224Smckusick tp = &dmz_tty[unit]; 24925224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 25025224Smckusick 25125224Smckusick priority = spl5(); 25225224Smckusick if ((tp->t_ispeed) == 0) { 25325224Smckusick tp->t_state |= TS_HUPCLS; 25425224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 25525224Smckusick splx(priority); 25625224Smckusick return; 25725224Smckusick } 25825224Smckusick 25925224Smckusick line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8); 26025224Smckusick line_control = DMZ_LCE; 26125224Smckusick 26225224Smckusick if ((tp->t_ispeed) == B134) 26325224Smckusick line_parameters |= DMZ_6BT | DMZ_PEN; 26425224Smckusick else if (tp->t_flags & (RAW | LITOUT)) 26525224Smckusick line_parameters |= DMZ_8BT; 26625224Smckusick else 26725224Smckusick line_parameters |= DMZ_7BT | DMZ_PEN; 26825224Smckusick 26925224Smckusick if (tp->t_flags & EVENP) 27025224Smckusick line_parameters |= DMZ_EPR; 27125224Smckusick if ((tp->t_ospeed) == B110) 27225224Smckusick line_parameters |= DMZ_SCD; 27325224Smckusick 27425224Smckusick line_parameters |= (unit & 07); 27525224Smckusick 27625224Smckusick dmz_addr->octet[octet].octet_lprm = line_parameters; 27725224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 27825224Smckusick dmz_addr->octet[octet].octet_lctmr = 27925224Smckusick (dmz_addr->octet[octet].octet_lctmr | (line_control & 0xff)); 28025224Smckusick 28125224Smckusick splx(priority); 28225224Smckusick return; 28325224Smckusick } 28425224Smckusick 28525224Smckusick /* ARGSUSED */ 28625224Smckusick dmzclose(device, flag) 28725224Smckusick dev_t device; 28825224Smckusick int flag; 28925224Smckusick { 29025224Smckusick register struct tty *tp; 29125224Smckusick register int unit; 29225224Smckusick 29325224Smckusick unit = minor(device); 29425224Smckusick tp = &dmz_tty[unit]; 29525224Smckusick 29625224Smckusick /* 29725224Smckusick * Break, hang-up and close the modem. 29825224Smckusick */ 29925224Smckusick (void) dmzmctl(unit, DMZ_BRK, DMBIC); 30025224Smckusick if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 30125224Smckusick (void) dmzmctl(unit, DMZ_OFF, DMSET); 30225224Smckusick ttyclose(tp); 30325224Smckusick return; 30425224Smckusick } 30525224Smckusick 30625224Smckusick dmzreset(uban) 30725224Smckusick int uban; 30825224Smckusick { 30925224Smckusick register int controller, unit; 31025224Smckusick register struct tty *tp; 31125224Smckusick register struct uba_device *ui; 31225224Smckusick register struct dmzdevice *dmz_addr; 31325224Smckusick int i; 31425224Smckusick int octet; 31525224Smckusick 31625224Smckusick if (dmz_ubinfo[uban] == 0) 31725224Smckusick return; 31825224Smckusick 31925224Smckusick dmz_ubinfo[uban] = uballoc(uban, (caddr_t) cfree, nclist * sizeof(struct cblock), 0); 32025224Smckusick cbase[uban] = dmz_ubinfo[uban] & 0x3ffff; 32125224Smckusick 32225224Smckusick for (controller = 0; controller < NDMZ; controller++) { 32325224Smckusick ui = dmzinfo[controller]; 32425224Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 32525224Smckusick continue; 32625224Smckusick printf("dmz%d ", controller); 32725224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 32825224Smckusick 32925224Smckusick for (octet = 0; octet < 3; octet++) 33025224Smckusick if ((dmzact[controller] & (1 << octet)) != 0) { 33125224Smckusick dmz_addr->octet[octet].octet_csr |= DMZ_IE; 33225224Smckusick dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; 33325224Smckusick } 33425224Smckusick 33525224Smckusick unit = controller * 24; 33625224Smckusick 33725224Smckusick /* 33825224Smckusick * If a unit is open or waiting for open to complete, 33925224Smckusick * reset it. 34025224Smckusick */ 34125224Smckusick for (i = 0; i < 24; i++) { 34225224Smckusick dmz_softc[unit].dmz_state = 0; 34325224Smckusick tp = &dmz_tty[unit]; 34425224Smckusick if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) { 34525224Smckusick dmzparam(unit); 34625224Smckusick (void) dmzmctl(unit, DMZ_ON, DMSET); 34725224Smckusick tp->t_state &= ~TS_BUSY; 34825224Smckusick dmzstart(tp); 34925224Smckusick } 35025224Smckusick unit++; 35125224Smckusick } 35225224Smckusick } 35325224Smckusick return; 35425224Smckusick } 35525224Smckusick 35625224Smckusick dmzread(device, uio) 35725224Smckusick dev_t device; 35825224Smckusick struct uio *uio; 35925224Smckusick { 36025224Smckusick register struct tty *tp; 36125224Smckusick int xstatus; 36225224Smckusick 36325224Smckusick tp = &dmz_tty[minor(device)]; 36425224Smckusick xstatus = (*linesw[tp->t_line].l_read)(tp, uio); 36525224Smckusick return (xstatus); 36625224Smckusick } 36725224Smckusick 36825224Smckusick dmzwrite(device, uio) 36925224Smckusick dev_t device; 37025224Smckusick struct uio *uio; 37125224Smckusick { 37225224Smckusick register struct tty *tp; 37325224Smckusick int xstatus; 37425224Smckusick 37525224Smckusick tp = &dmz_tty[minor(device)]; 37625224Smckusick xstatus = (*linesw[tp->t_line].l_write)(tp, uio); 37725224Smckusick return (xstatus); 37825224Smckusick } 37925224Smckusick 38025224Smckusick dmzrinta(controller) 38125224Smckusick int controller; 38225224Smckusick { 38325224Smckusick dmzrint(controller, 0); 38425224Smckusick } 38525224Smckusick 38625224Smckusick dmzrintb(controller) 38725224Smckusick int controller; 38825224Smckusick { 38925224Smckusick dmzrint(controller, 1); 39025224Smckusick } 39125224Smckusick 39225224Smckusick dmzrintc(controller) 39325224Smckusick int controller; 39425224Smckusick { 39525224Smckusick dmzrint(controller, 2); 39625224Smckusick } 39725224Smckusick 39825224Smckusick dmzrint(controller, octet) 39925224Smckusick int controller; 40025224Smckusick register int octet; 40125224Smckusick { 40225224Smckusick register struct tty *tp; 40325224Smckusick register int character; 40425224Smckusick register struct dmzdevice *dmz_addr; 40525224Smckusick register struct tty *tp0; 40625224Smckusick register int unit; 40725224Smckusick register struct uba_device *ui; 408*25396Skarels int overrun; 40925224Smckusick 41025224Smckusick overrun = 0; 41125224Smckusick ui = dmzinfo[controller]; 41225224Smckusick if (ui == 0 || ui->ui_alive == 0) 41325224Smckusick return; 41425224Smckusick dmz_addr = (struct dmzdevice *) ui->ui_addr; 41525224Smckusick tp0 = &dmz_tty[controller * 24]; 41625224Smckusick 41725224Smckusick while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) { 41825224Smckusick unit = (character >> 8) & 07; /* unit is bits 8-10 of rb */ 41925224Smckusick tp = tp0 + (octet * 8 + unit); 42025224Smckusick 421*25396Skarels if (character & DMZ_DSC && 422*25396Skarels (dmzsoftCAR[controller] & (1 << (octet * 8 + unit))) == 0) { 423*25396Skarels dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | unit; 424*25396Skarels if (dmz_addr->octet[octet].octet_rms & DMZ_CAR) 425*25396Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 426*25396Skarels else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 427*25396Skarels dmz_addr->octet[octet].octet_csr = 428*25396Skarels DMZ_IE | IR_LCTMR | unit; 429*25396Skarels dmz_addr->octet[octet].octet_lctmr = 430*25396Skarels dmz_addr->octet[octet].octet_lctmr & 431*25396Skarels ((DMZ_OFF<<8) | 0xff); 43225224Smckusick } 43325224Smckusick continue; 43425224Smckusick } 43525224Smckusick 436*25396Skarels if ((tp->t_state&TS_ISOPEN)==0) { 437*25396Skarels wakeup((caddr_t)&tp->t_rawq); 438*25396Skarels #ifdef PORTSELECTOR 439*25396Skarels if ((tp->t_state&TS_WOPEN) == 0) 440*25396Skarels #endif 441*25396Skarels continue; 44225224Smckusick } 44325224Smckusick 44425224Smckusick if (character & DMZ_PE) { 44525224Smckusick if ((tp->t_flags & (EVENP | ODDP)) == EVENP || 44625224Smckusick (tp->t_flags & (EVENP | ODDP)) == ODDP) 44725224Smckusick continue; 44825224Smckusick } 44925224Smckusick 45025224Smckusick if ((character & DMZ_DO) && overrun == 0) { 45125224Smckusick printf("dmz%d: silo overflow\n", controller); 45225224Smckusick overrun = 1; 45325224Smckusick } 45425224Smckusick 45525224Smckusick if (character & DMZ_FE) { 45625224Smckusick if (tp->t_flags & RAW) 45725224Smckusick character = 0; 45825224Smckusick else 45925224Smckusick character = tp->t_intrc; 46025224Smckusick } 46125224Smckusick 46225224Smckusick (*linesw[tp->t_line].l_rint)(character, tp); 46325224Smckusick } 46425224Smckusick 46525224Smckusick return; 46625224Smckusick } 46725224Smckusick 46825224Smckusick dmzxinta(controller) 46925224Smckusick int controller; 47025224Smckusick { 47125224Smckusick dmzxint(controller, 0); 47225224Smckusick } 47325224Smckusick 47425224Smckusick dmzxintb(controller) 47525224Smckusick int controller; 47625224Smckusick { 47725224Smckusick dmzxint(controller, 1); 47825224Smckusick } 47925224Smckusick 48025224Smckusick dmzxintc(controller) 48125224Smckusick int controller; 48225224Smckusick { 48325224Smckusick dmzxint(controller, 2); 48425224Smckusick } 48525224Smckusick 48625224Smckusick dmzxint(controller, octet) 48725224Smckusick int controller; 48825224Smckusick register int octet; 48925224Smckusick { 49025224Smckusick register struct tty *tp; 49125224Smckusick register struct dmzdevice *dmz_addr; 49225224Smckusick register struct uba_device *ui; 49325224Smckusick register int unit, t; 49425224Smckusick int priority; 49525224Smckusick 49625224Smckusick ui = dmzinfo[controller]; 49725224Smckusick dmz_addr = (struct dmzdevice *)ui->ui_addr; 49825224Smckusick 49925224Smckusick priority = spl5(); 50025224Smckusick 50125224Smckusick while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) { 50225224Smckusick unit = controller * 24 + (octet * 8 + ((t>>8) & 07)); 50325224Smckusick tp = &dmz_tty[unit]; 50425224Smckusick tp->t_state &= ~TS_BUSY; 50525224Smckusick 50625224Smckusick if (t & DMZ_NXM) 50725224Smckusick printf("dmz%d: NXM line %d\n", controller, 50825224Smckusick octet * 8 + (unit & 07)); 50925224Smckusick 51025224Smckusick if (tp->t_state & TS_FLUSH) { 51125224Smckusick tp->t_state &= ~TS_FLUSH; 51225224Smckusick dmz_addr->octet[octet].octet_csr = 51325224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 51425224Smckusick dmz_addr->octet[octet].octet_lctmr = 51525224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 51625224Smckusick } else 51725224Smckusick if (dmz_softc[unit].dmz_state & ST_DMA) 51825224Smckusick ndflush(&tp->t_outq, dmz_softc[unit].dmz_count); 51925224Smckusick dmz_softc[unit].dmz_state = 0; 52025224Smckusick 52125224Smckusick if (tp->t_line) 52225224Smckusick (*linesw[tp->t_line].l_start)(tp); 52325224Smckusick else 52425224Smckusick dmzstart(tp); 52525224Smckusick } 52625224Smckusick 52725224Smckusick splx(priority); 52825224Smckusick return; 52925224Smckusick } 53025224Smckusick 53125224Smckusick dmzstart(tp) 53225224Smckusick register struct tty *tp; 53325224Smckusick { 53425224Smckusick register struct dmzdevice *dmz_addr; 53525224Smckusick register int unit, nch, room; 53625224Smckusick int controller, octet; 53725224Smckusick int priority, car, use_dma; 53825224Smckusick register int i; 53925224Smckusick register char *cp; 54025224Smckusick 54125224Smckusick unit = minor(tp->t_dev); 54225224Smckusick controller = DMZ(unit); 54325224Smckusick octet = OCTET(unit); 54425224Smckusick dmz_addr = (struct dmzdevice *)tp->t_addr; 54525224Smckusick 54625224Smckusick priority = spl5(); 54725224Smckusick 54825224Smckusick if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 54925224Smckusick goto out; 55025224Smckusick 55125224Smckusick /* 55225224Smckusick * If the transmitter has been disabled, reenable it. 55325224Smckusick * If the transmitter was disabled before the xint (the 55425224Smckusick * ST_INBUSY was still on), then reset the BUSY state and 55525224Smckusick * we will wait for the interrupt. If !TS_BUSY, we already 55625224Smckusick * saw the interrupt so we can start another transmission. 55725224Smckusick */ 55825224Smckusick if (dmz_softc[unit].dmz_state & ST_TXOFF) { 55925224Smckusick dmz_addr->octet[octet].octet_csr = 56025224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 56125224Smckusick dmz_addr->octet[octet].octet_lctmr = 56225224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 56325224Smckusick dmz_softc[unit].dmz_state &= ~ST_TXOFF; 56425224Smckusick if (dmz_softc[unit].dmz_state & ST_INBUSY) { 56525224Smckusick dmz_softc[unit].dmz_state &= ~ST_INBUSY; 56625224Smckusick tp->t_state |= TS_BUSY; 56725224Smckusick goto out; 56825224Smckusick } 56925224Smckusick } 57025224Smckusick 57125224Smckusick if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 57225224Smckusick if (tp->t_state & TS_ASLEEP) { 57325224Smckusick tp->t_state &= ~TS_ASLEEP; 57425224Smckusick wakeup((caddr_t)&tp->t_outq); 57525224Smckusick } 57625224Smckusick if (tp->t_wsel) { 57725224Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 57825224Smckusick tp->t_wsel = 0; 57925224Smckusick tp->t_state &= ~TS_WCOLL; 58025224Smckusick } 58125224Smckusick } 58225224Smckusick 58325224Smckusick if (tp->t_outq.c_cc == 0) 58425224Smckusick goto out; 58525224Smckusick if (tp->t_flags & (RAW | LITOUT)) 58625224Smckusick nch = ndqb(&tp->t_outq, 0); 58725224Smckusick else { 58825224Smckusick nch = ndqb(&tp->t_outq, 0200); 58925224Smckusick if (nch == 0) { 59025224Smckusick nch = getc(&tp->t_outq); 59125224Smckusick timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6); 59225224Smckusick tp->t_state |= TS_TIMEOUT; 59325224Smckusick goto out; 59425224Smckusick } 59525224Smckusick } 59625224Smckusick 59725224Smckusick /* 59825224Smckusick * Should we use DMA or SILO mode? 59925224Smckusick * If nch is greater than DO_DMA_COUNT then DMA. 60025224Smckusick */ 60125224Smckusick if (nch) { 60225224Smckusick dmz_addr->octet[octet].octet_csr = 60325224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 60425224Smckusick dmz_addr->octet[octet].octet_lctmr = 60525224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); 60625224Smckusick tp->t_state |= TS_BUSY; 60725224Smckusick 60825224Smckusick use_dma = FALSE; 60925224Smckusick room = DMZ_SIZ; 61025224Smckusick 61125224Smckusick if (nch > DO_DMA_COUNT) 61225224Smckusick use_dma = TRUE; 61325224Smckusick 61425224Smckusick if (use_dma && dmz_dma_on) { 61525224Smckusick car = UBACVT(tp->t_outq.c_cf, 61625224Smckusick dmzinfo[controller]->ui_ubanum); 61725224Smckusick dmz_softc[unit].dmz_count = nch; 61825224Smckusick dmz_softc[unit].dmz_state |= ST_DMA; 61925224Smckusick dmz_addr->octet[octet].octet_csr = 62025224Smckusick DMZ_IE | IR_TBA | (unit & 07); 62125224Smckusick dmz_addr->octet[octet].octet_tba = car; 62225224Smckusick dmz_addr->octet[octet].octet_tcc = 62325224Smckusick ((car >> 2) & 0xc000) | nch; 62425224Smckusick } else { 62525224Smckusick dmz_softc[unit].dmz_state &= ~ST_DMA; 62625224Smckusick cp = tp->t_outq.c_cf; 62725224Smckusick nch = MIN(nch, room); 62825224Smckusick dmz_addr->octet[octet].octet_csr = 62925224Smckusick DMZ_IE | IR_TBUF | (unit & 07); 63025224Smckusick for (i = 0; i < nch; i++) 63125224Smckusick dmz_addr->octet[octet].octet_tbf = *cp++ ; 63225224Smckusick ndflush(&tp->t_outq, nch); 63325224Smckusick } 63425224Smckusick } 63525224Smckusick 63625224Smckusick out: 63725224Smckusick splx(priority); 63825224Smckusick return; 63925224Smckusick } 64025224Smckusick 64125224Smckusick /* ARGSUSED */ 64225224Smckusick dmzstop(tp, flag) 64325224Smckusick register struct tty *tp; 64425224Smckusick { 64525224Smckusick register struct dmzdevice *dmz_addr; 64625224Smckusick register int unit, priority, octet; 64725224Smckusick 64825224Smckusick priority = spl5(); 64925224Smckusick dmz_addr = (struct dmzdevice *) tp->t_addr; 65025224Smckusick unit = minor(tp->t_dev); 65125224Smckusick octet = OCTET(unit); 65225224Smckusick 65325224Smckusick dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE; 65425224Smckusick dmz_addr->octet[octet].octet_lctmr = 65525224Smckusick (dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE); 65625224Smckusick dmz_softc[unit].dmz_state |= ST_TXOFF; 65725224Smckusick if ((tp->t_state & TS_TTSTOP) == 0) { 65825224Smckusick tp->t_state |= (TS_FLUSH | TS_BUSY); 65925224Smckusick dmz_addr->octet[octet].octet_lctmr = 66025224Smckusick (dmz_addr->octet[octet].octet_lctmr | DMZ_FLS); 66125224Smckusick } else if (tp->t_state & TS_BUSY) { 66225224Smckusick dmz_softc[unit].dmz_state |= ST_INBUSY; 66325224Smckusick tp->t_state &= ~TS_BUSY; 66425224Smckusick } 66525224Smckusick 66625224Smckusick splx(priority); 66725224Smckusick return; 66825224Smckusick } 66925224Smckusick 67025224Smckusick /* ARGSUSED */ 67125224Smckusick dmzioctl(device, command, data, flag) 67225224Smckusick dev_t device; 67325224Smckusick caddr_t data; 67425224Smckusick { 67525224Smckusick register struct tty *tp; 67625224Smckusick register int unit; 67725224Smckusick int error; 67825224Smckusick 67925224Smckusick unit = minor(device); 68025224Smckusick tp = &dmz_tty[unit]; 68125224Smckusick 68225224Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag); 68325224Smckusick if (error >= 0) 68425224Smckusick return (error); 68525224Smckusick error = ttioctl(tp, command, data, flag); 68625224Smckusick if (error >= 0) { 68725224Smckusick if (command == TIOCSETP || command == TIOCSETN) 68825224Smckusick dmzparam(unit); 68925224Smckusick return (error); 69025224Smckusick } 69125224Smckusick 69225224Smckusick switch (command) { 69325224Smckusick case TIOCSBRK: 69425224Smckusick (void) dmzmctl(device, DMZ_BRK, DMBIS); 69525224Smckusick break; 69625224Smckusick case TIOCCBRK: 69725224Smckusick (void) dmzmctl(device, DMZ_BRK, DMBIC); 69825224Smckusick break; 69925224Smckusick case TIOCSDTR: 70025224Smckusick (void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIS); 70125224Smckusick break; 70225224Smckusick case TIOCCDTR: 70325224Smckusick (void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIC); 70425224Smckusick break; 70525224Smckusick case TIOCMSET: 70625224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMSET); 70725224Smckusick break; 70825224Smckusick case TIOCMBIS: 70925224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMBIS); 71025224Smckusick break; 71125224Smckusick case TIOCMBIC: 71225224Smckusick (void) dmzmctl(device, dmtodmz(*(int *)data), DMBIC); 71325224Smckusick break; 71425224Smckusick case TIOCMGET: 71525224Smckusick *(int *)data = dmztodm(dmzmctl(device, 0, DMGET)); 71625224Smckusick break; 71725224Smckusick default: 71825224Smckusick return (ENOTTY); 71925224Smckusick } 72025224Smckusick return (0); 72125224Smckusick } 72225224Smckusick 72325224Smckusick dmzmctl(device, bits, how) 72425224Smckusick dev_t device; 72525224Smckusick int bits, how; 72625224Smckusick { 72725224Smckusick register struct dmzdevice *dmz_addr; 72825224Smckusick register int unit, modem_status, line_control; 72925224Smckusick register int temp; 73025224Smckusick int priority; 73125224Smckusick int octet; 73225224Smckusick 73325224Smckusick unit = minor(device); 73425224Smckusick octet = OCTET(unit); 73525224Smckusick dmz_addr = (struct dmzdevice *) dmz_tty[unit].t_addr; 73625224Smckusick 73725224Smckusick priority = spl5(); 73825224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | (unit & 07); 73925224Smckusick modem_status = dmz_addr->octet[octet].octet_rms << 8; 74025224Smckusick 74125224Smckusick dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); 74225224Smckusick temp = dmz_addr->octet[octet].octet_lctmr; 74325224Smckusick modem_status |= ((temp>>8) & (0x1f)); 744*25396Skarels line_control = (temp & (0x3f)); 74525224Smckusick 74625224Smckusick if (line_control & DMZ_BRK) 74725224Smckusick modem_status |= DMZ_BRK; 74825224Smckusick 74925224Smckusick switch (how) { 75025224Smckusick case DMSET: 75125224Smckusick modem_status = (modem_status & 0xff00) | bits; 75225224Smckusick break; 75325224Smckusick case DMBIS: 75425224Smckusick modem_status |= bits; 75525224Smckusick break; 75625224Smckusick case DMBIC: 75725224Smckusick modem_status &= ~bits; 75825224Smckusick break; 75925224Smckusick case DMGET: 76025224Smckusick (void) splx(priority); 76125224Smckusick return (modem_status); 76225224Smckusick } 76325224Smckusick 76425224Smckusick if (modem_status & DMZ_BRK) 76525224Smckusick line_control |= DMZ_RBK; 76625224Smckusick else 76725224Smckusick line_control &= ~DMZ_RBK; 76825224Smckusick modem_status &= ~DMZ_BRK; 76925224Smckusick 77025224Smckusick dmz_addr->octet[octet].octet_csr = 77125224Smckusick DMZ_IE | IR_LCTMR | (unit & 07); 77225224Smckusick dmz_addr->octet[octet].octet_lctmr = 77325224Smckusick ((modem_status & 0x1f) << 8) | (line_control & 0x3f); 77425224Smckusick 77525224Smckusick (void) splx(priority); 77625224Smckusick return (modem_status); 77725224Smckusick } 77825224Smckusick 77925224Smckusick /* 78025224Smckusick * Routine to convert modem status from dm to dmz format. 78125224Smckusick * Pull bits 1 & 3 through unchanged. If dm secondary transmit bit is set, 78225224Smckusick * and/or dm request to send bit is set, and/or dm user modem signal bit 78325224Smckusick * is set, set the corresponding dmz bits. 78425224Smckusick */ 78525224Smckusick dmtodmz(bits) 78625224Smckusick register int bits; 78725224Smckusick { 78825224Smckusick register int b; 78925224Smckusick 79025224Smckusick b = bits & 012; 79125224Smckusick if (bits & DM_ST) 79225224Smckusick b |= DMZ_RAT; 79325224Smckusick if (bits & DM_RTS) 79425224Smckusick b |= DMZ_RTS; 79525224Smckusick if (bits & DM_USR) 79625224Smckusick b |= DMZ_USW; 79725224Smckusick return (b); 79825224Smckusick } 79925224Smckusick 80025224Smckusick /* 80125224Smckusick * Routine to convert modem status from dmz to dm format. Pull bits 1 & 3 80225224Smckusick * through unchanged. Pull bits 11 - 15 through as bits 4 - 8 and set bit 80325224Smckusick * 0 to dm line enable. If dmz user modem signal bit set, and/or dmz 80425224Smckusick * request to send bit set, then set the corresponding dm bit also. 80525224Smckusick */ 80625224Smckusick dmztodm(bits) 80725224Smckusick register int bits; 80825224Smckusick { 80925224Smckusick register int b; 81025224Smckusick 81125224Smckusick b = (bits & 012) | ((bits >> 7) & 0760) | DM_LE; 81225224Smckusick if (bits & DMZ_USR) 81325224Smckusick b |= DM_USR; 81425224Smckusick if (bits & DMZ_RTS) 81525224Smckusick b |= DM_RTS; 81625224Smckusick return (b); 81725224Smckusick } 81825224Smckusick #endif 819