123324Smckusick /* 223324Smckusick * Copyright (c) 1982 Regents of the University of California. 323324Smckusick * All rights reserved. The Berkeley software License Agreement 423324Smckusick * specifies the terms and conditions for redistribution. 523324Smckusick * 6*26312Skarels * @(#)dmf.c 6.14 (Berkeley) 02/21/86 723324Smckusick */ 86940Ssam 96940Ssam #include "dmf.h" 106940Ssam #if NDMF > 0 116940Ssam /* 126940Ssam * DMF32 driver 136940Ssam * 1421955Sbloom * 156940Ssam * TODO: 166940Ssam * test with modem 176940Ssam * load as much as possible into silo 186940Ssam * use auto XON/XOFF 196940Ssam * test reset code 2021955Sbloom **************************** 2121955Sbloom * DMF32 line printer driver 2221955Sbloom * 2321955Sbloom * the line printer on dmfx is indicated by a minor device code of 128+x 2421955Sbloom * 2521955Sbloom * the flags field of the config file is interpreted like so: 2621955Sbloom * bits meaning 2721955Sbloom * ---- ------- 2821955Sbloom * 0-7 soft carrier bits for ttys part of dmf32 2921955Sbloom * 8-15 number of cols/line on the line printer 3021955Sbloom * if 0, 132 will be used. 3121955Sbloom * 16-23 number of lines/page on the line printer 3221955Sbloom * if 0, 66 will be used. 3321955Sbloom * 346940Ssam */ 359772Ssam #include "../machine/pte.h" 369772Ssam 376940Ssam #include "bk.h" 3816063Skarels #include "uba.h" 3917124Sbloom #include "param.h" 4017124Sbloom #include "conf.h" 4117124Sbloom #include "dir.h" 4217124Sbloom #include "user.h" 4317124Sbloom #include "ioctl.h" 4417124Sbloom #include "tty.h" 4517124Sbloom #include "map.h" 4617124Sbloom #include "buf.h" 4717124Sbloom #include "vm.h" 4817124Sbloom #include "bkmac.h" 4917124Sbloom #include "clist.h" 5017124Sbloom #include "file.h" 5117124Sbloom #include "uio.h" 5221955Sbloom #include "kernel.h" 5318312Sralph #include "syslog.h" 546940Ssam 5517124Sbloom #include "ubareg.h" 5617124Sbloom #include "ubavar.h" 5717124Sbloom #include "dmfreg.h" 588473Sroot 596940Ssam /* 606940Ssam * Definition of the driver for the auto-configuration program. 616940Ssam */ 626940Ssam int dmfprobe(), dmfattach(), dmfrint(), dmfxint(); 6321955Sbloom int dmflint(); 646940Ssam struct uba_device *dmfinfo[NDMF]; 656940Ssam u_short dmfstd[] = { 0 }; 666940Ssam struct uba_driver dmfdriver = 676940Ssam { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo }; 686940Ssam 6925449Skarels int dmf_timeout = 10; /* silo timeout, in ms */ 7021955Sbloom int dmf_mindma = 4; /* don't dma below this point */ 7121955Sbloom 726940Ssam /* 736940Ssam * Local variables for the driver 746940Ssam */ 756940Ssam char dmf_speeds[] = 766940Ssam { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 }; 776940Ssam 7825449Skarels #ifndef PORTSELECTOR 7925449Skarels #define ISPEED B9600 8025449Skarels #define IFLAGS (EVENP|ODDP|ECHO) 8125449Skarels #else 8225449Skarels #define ISPEED B4800 8325449Skarels #define IFLAGS (EVENP|ODDP) 8425449Skarels #endif 8525449Skarels 866940Ssam struct tty dmf_tty[NDMF*8]; 876940Ssam char dmfsoftCAR[NDMF]; 8821955Sbloom 8921955Sbloom struct dmfl_softc 9021955Sbloom { 9121955Sbloom unsigned dmfl_state; /* soft state bits */ 9221955Sbloom unsigned dmfl_info; /* uba info */ 9321955Sbloom unsigned short dmfl_lines; /* lines per page (66 def.) */ 9421955Sbloom unsigned short dmfl_cols; /* cols per line (132 def.) */ 9521955Sbloom char dmfl_buf[DMFL_BUFSIZ]; 9621955Sbloom } dmfl_softc[NDMF]; 9721955Sbloom 9821955Sbloom /* 9921955Sbloom * convert device number into DMF line printer unit number 10021955Sbloom */ 10121955Sbloom #define DMFL_UNIT(d) (minor(d)&0xF) /* up to 16 DMFs */ 10221955Sbloom 10321955Sbloom #define ASLP 1 /* waiting for interrupt from dmf */ 10421955Sbloom #define OPEN 2 /* line printer is open */ 10521955Sbloom #define ERROR 4 /* error while printing, driver 10621955Sbloom refuses to do anything till closed */ 10721955Sbloom 1088778Sroot #ifndef lint 1098778Sroot int ndmf = NDMF*8; /* used by iostat */ 1108778Sroot #endif 1116940Ssam int dmfact; /* mask of active dmf's */ 1126940Ssam int dmfstart(), ttrstrt(); 1136940Ssam 1146940Ssam /* 1156940Ssam * The clist space is mapped by the driver onto each UNIBUS. 1166940Ssam * The UBACVT macro converts a clist space address for unibus uban 1176940Ssam * into an i/o space address for the DMA routine. 1186940Ssam */ 11916063Skarels int dmf_ubinfo[NUBA]; /* info about allocated unibus map */ 12025449Skarels int cbase[NUBA]; /* base address in unibus map */ 1216940Ssam #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 12221955Sbloom char dmf_dma[NDMF*8]; 1236940Ssam 1246940Ssam /* 1256940Ssam * Routine for configuration to set dmf interrupt. 1266940Ssam */ 1276940Ssam /*ARGSUSED*/ 1286940Ssam dmfprobe(reg, ctlr) 1296940Ssam caddr_t reg; 13021955Sbloom struct uba_device *ctlr; 1316940Ssam { 1326940Ssam register int br, cvec; /* these are ``value-result'' */ 1336940Ssam register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg; 13421955Sbloom register int i; 13521955Sbloom register unsigned int a; 13621955Sbloom static char *dmfdevs[]= 13721955Sbloom {"parallel","printer","synch","asynch"}; 13821955Sbloom unsigned int dmfoptions; 13925449Skarels static int (*intrv[3])() = { (int (*)())0, (int (*)())0, (int (*)())0 }; 1406940Ssam 1416940Ssam #ifdef lint 1426940Ssam br = 0; cvec = br; br = cvec; 1438808Sroot dmfxint(0); dmfrint(0); 1448808Sroot dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint(); 1456940Ssam #endif 14621955Sbloom /* 14721955Sbloom * Pick the usual size DMF vector here (don't decrement it here). 14821955Sbloom * grab configuration; note that the DMF32 14921955Sbloom * doesn't seem to put the right bits in this 15021955Sbloom * register until AFTER the interrupt vector is set. 15121955Sbloom */ 1526940Ssam br = 0x15; 15321955Sbloom cvec = (uba_hd[numuba].uh_lastiv - 4*8); 15425449Skarels dmfaddr->dmfccsr0 = (cvec >> 2); 15521955Sbloom dmfoptions = dmfaddr->dmfccsr0 & DMFC_CONFMASK; 15621955Sbloom 15721955Sbloom /* catch a couple of special cases: Able vmz/32n and vmz/lp */ 15821955Sbloom if (dmfoptions == DMFC_ASYNC) { 15925449Skarels /* Async portion only */ 16025449Skarels 16125449Skarels cvec = (uba_hd[numuba].uh_lastiv -= 8); 16225449Skarels dmfaddr->dmfccsr0 = (cvec - 2*8) >> 2; 16325449Skarels intrv[0] = ctlr->ui_intr[4]; 16425449Skarels intrv[1] = ctlr->ui_intr[5]; 16525449Skarels ctlr->ui_intr = intrv; 166*26312Skarels } else if (dmfoptions == DMFC_LP) { 16725449Skarels /* LP portion only */ 16821955Sbloom 16925449Skarels cvec = (uba_hd[numuba].uh_lastiv -= 8); 17025449Skarels ctlr->ui_intr = &ctlr->ui_intr[6]; 171*26312Skarels } else if (dmfoptions == (DMFC_LP|DMFC_ASYNC)) { 17225449Skarels /* LP ans Async portions only */ 17325449Skarels 17425449Skarels cvec = (uba_hd[numuba].uh_lastiv -= 2*8); 17525449Skarels ctlr->ui_intr = &ctlr->ui_intr[4]; 176*26312Skarels } else { 17725449Skarels /* All other configurations get everything */ 17821955Sbloom 17921955Sbloom cvec = (uba_hd[numuba].uh_lastiv -= 4*8); 18021955Sbloom } 18125449Skarels a = (dmfoptions >> 12) & 0xf; 18225449Skarels printf("dmf%d:", ctlr->ui_unit); 183*26312Skarels for (i = 0; a != 0; ++i, a >>= 1) { 184*26312Skarels if (a & 1) 18525449Skarels printf(" %s",dmfdevs[i]); 18625449Skarels } 18725449Skarels printf(".\n"); 18821955Sbloom 18921955Sbloom if (dmfoptions & DMFC_LP) 19021955Sbloom dmfaddr->dmfl[0] = DMFL_RESET; 1917412Skre return (sizeof (struct dmfdevice)); 1926940Ssam } 1936940Ssam 1946940Ssam /* 1956940Ssam * Routine called to attach a dmf. 1966940Ssam */ 1976940Ssam dmfattach(ui) 1986940Ssam struct uba_device *ui; 1996940Ssam { 20021955Sbloom register int cols = (ui->ui_flags>>8) & 0xff; 20121955Sbloom register int lines = (ui->ui_flags>>16) & 0xff; 2026940Ssam 20321955Sbloom dmfsoftCAR[ui->ui_unit] = ui->ui_flags & 0xff; 20421955Sbloom dmfl_softc[ui->ui_unit].dmfl_cols = cols==0?DMFL_DEFCOLS:cols; 20521955Sbloom dmfl_softc[ui->ui_unit].dmfl_lines = lines==0?DMFL_DEFLINES:lines; 20626221Skarels cbase[ui->ui_ubanum] = -1; 2076940Ssam } 2086940Ssam 2096940Ssam 2106940Ssam /* 2116940Ssam * Open a DMF32 line, mapping the clist onto the uba if this 2126940Ssam * is the first dmf on this uba. Turn on this dmf if this is 2136940Ssam * the first use of it. 2146940Ssam */ 2156940Ssam /*ARGSUSED*/ 2166940Ssam dmfopen(dev, flag) 2176940Ssam dev_t dev; 2186940Ssam { 2196940Ssam register struct tty *tp; 2206940Ssam register int unit, dmf; 2216940Ssam register struct dmfdevice *addr; 2226940Ssam register struct uba_device *ui; 2236940Ssam int s; 2246940Ssam 2256940Ssam unit = minor(dev); 226*26312Skarels if (unit & 0200) 227*26312Skarels return (dmflopen(dev,flag)); 2286940Ssam dmf = unit >> 3; 2298567Sroot if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) 2308567Sroot return (ENXIO); 2316940Ssam tp = &dmf_tty[unit]; 2328567Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2338567Sroot return (EBUSY); 2346940Ssam addr = (struct dmfdevice *)ui->ui_addr; 2356940Ssam tp->t_addr = (caddr_t)addr; 2366940Ssam tp->t_oproc = dmfstart; 2376971Ssam tp->t_state |= TS_WOPEN; 2386940Ssam /* 2396940Ssam * While setting up state for this uba and this dmf, 2406940Ssam * block uba resets which can clear the state. 2416940Ssam */ 24221955Sbloom s = spltty(); 24326221Skarels if (cbase[ui->ui_ubanum] == -1) { 2446940Ssam dmf_ubinfo[ui->ui_ubanum] = 2456940Ssam uballoc(ui->ui_ubanum, (caddr_t)cfree, 2466940Ssam nclist*sizeof(struct cblock), 0); 24726221Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(dmf_ubinfo[ui->ui_ubanum]); 2486940Ssam } 2496940Ssam if ((dmfact&(1<<dmf)) == 0) { 2506940Ssam addr->dmfcsr |= DMF_IE; 2516940Ssam dmfact |= (1<<dmf); 25221955Sbloom addr->dmfrsp = dmf_timeout; 2536940Ssam } 2546940Ssam splx(s); 2556940Ssam /* 2566940Ssam * If this is first open, initialze tty state to default. 2576940Ssam */ 2586971Ssam if ((tp->t_state&TS_ISOPEN) == 0) { 2596940Ssam ttychars(tp); 26025449Skarels tp->t_ispeed = ISPEED; 26125449Skarels tp->t_ospeed = ISPEED; 26225449Skarels tp->t_flags = IFLAGS; 2636940Ssam dmfparam(unit); 2646940Ssam } 2656940Ssam /* 2666940Ssam * Wait for carrier, then process line discipline specific open. 2676940Ssam */ 2686940Ssam if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) || 2696940Ssam (dmfsoftCAR[dmf] & (1<<(unit&07)))) 2706971Ssam tp->t_state |= TS_CARR_ON; 27121955Sbloom s = spltty(); 2726971Ssam while ((tp->t_state & TS_CARR_ON) == 0) { 2736971Ssam tp->t_state |= TS_WOPEN; 2746940Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 2756940Ssam } 2766940Ssam splx(s); 2778567Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 2786940Ssam } 2796940Ssam 2806940Ssam /* 2816940Ssam * Close a DMF32 line. 2826940Ssam */ 2836940Ssam /*ARGSUSED*/ 2846940Ssam dmfclose(dev, flag) 2856940Ssam dev_t dev; 2866940Ssam int flag; 2876940Ssam { 2886940Ssam register struct tty *tp; 2896940Ssam register unit; 2906940Ssam 2916940Ssam unit = minor(dev); 292*26312Skarels if (unit & 0200) { 293*26312Skarels dmflclose(dev,flag); 294*26312Skarels return; 295*26312Skarels } 29621955Sbloom 2976940Ssam tp = &dmf_tty[unit]; 2986940Ssam (*linesw[tp->t_line].l_close)(tp); 2998702Sroot (void) dmfmctl(unit, DMF_BRK, DMBIC); 3006971Ssam if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3018702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 3026940Ssam ttyclose(tp); 3036940Ssam } 3046940Ssam 3057726Sroot dmfread(dev, uio) 3066940Ssam dev_t dev; 3077726Sroot struct uio *uio; 3086940Ssam { 3096940Ssam register struct tty *tp; 3106940Ssam 311*26312Skarels if (minor(dev) & 0200) 31221955Sbloom return(ENXIO); 3136940Ssam tp = &dmf_tty[minor(dev)]; 3147726Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 3156940Ssam } 3166940Ssam 3177832Sroot dmfwrite(dev, uio) 3186940Ssam dev_t dev; 3197832Sroot struct uio *uio; 3206940Ssam { 3216940Ssam register struct tty *tp; 3226940Ssam 323*26312Skarels if (minor(dev) & 0200) 324*26312Skarels return (dmflwrite(dev,uio)); 3256940Ssam tp = &dmf_tty[minor(dev)]; 3268530Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 3276940Ssam } 3286940Ssam 3296940Ssam /* 3306940Ssam * DMF32 receiver interrupt. 3316940Ssam */ 3326940Ssam dmfrint(dmf) 3336940Ssam int dmf; 3346940Ssam { 3356940Ssam register c; 336*26312Skarels register struct tty *tp; 3376940Ssam register struct dmfdevice *addr; 3386940Ssam register struct tty *tp0; 33921955Sbloom int unit; 34025449Skarels int overrun = 0; 341*26312Skarels register struct uba_device *ui; 3426940Ssam 343*26312Skarels ui = dmfinfo[dmf]; 344*26312Skarels if (ui == 0 || ui->ui_alive == 0) 345*26312Skarels return; 346*26312Skarels addr = (struct dmfdevice *)ui->ui_addr; 34721955Sbloom tp0 = &dmf_tty[dmf * 8]; 3486940Ssam /* 3496940Ssam * Loop fetching characters from the silo for this 3506940Ssam * dmf until there are no more in the silo. 3516940Ssam */ 3526940Ssam while ((c = addr->dmfrbuf) < 0) { 35321955Sbloom 35421955Sbloom unit = (c >> 8) & 07; 35521955Sbloom tp = tp0 + unit; 3566940Ssam if (c & DMF_DSC) { 35721955Sbloom addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 35825449Skarels if (addr->dmfrms & DMF_CAR) 35925449Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 360*26312Skarels else if ((dmfsoftCAR[dmf] & (1 << unit)) == 0 && 36125449Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 36225449Skarels addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 36325449Skarels addr->dmflctms = DMFLCR_ENA; 3646940Ssam } 3656940Ssam continue; 3666940Ssam } 367*26312Skarels if ((tp->t_state&TS_ISOPEN) == 0) { 36825449Skarels wakeup((caddr_t)&tp->t_rawq); 36925449Skarels #ifdef PORTSELECTOR 370*26312Skarels if ((tp->t_state & TS_WOPEN) == 0) 37125449Skarels #endif 37225449Skarels continue; 3736940Ssam } 37421956Sbloom if (c & (DMF_PE|DMF_DO|DMF_FE)) { 37521955Sbloom if (c & DMF_PE) 376*26312Skarels if ((tp->t_flags & (EVENP|ODDP)) == EVENP 377*26312Skarels || (tp->t_flags & (EVENP|ODDP)) == ODDP) 37821955Sbloom continue; 37921955Sbloom if ((c & DMF_DO) && overrun == 0) { 38024842Seric log(LOG_WARNING, "dmf%d: silo overflow\n", dmf); 38121955Sbloom overrun = 1; 38221955Sbloom } 38321955Sbloom if (c & DMF_FE) 38421955Sbloom /* 38521955Sbloom * At framing error (break) generate 38621955Sbloom * a null (in raw mode, for getty), or a 38721955Sbloom * interrupt (in cooked/cbreak mode). 38821955Sbloom */ 389*26312Skarels if (tp->t_flags & RAW) 39021955Sbloom c = 0; 39121955Sbloom else 39221955Sbloom c = tp->t_intrc; 3936940Ssam } 3946940Ssam #if NBK > 0 3956940Ssam if (tp->t_line == NETLDISC) { 3966940Ssam c &= 0177; 3976940Ssam BKINPUT(c, tp); 3986940Ssam } else 3996940Ssam #endif 4006940Ssam (*linesw[tp->t_line].l_rint)(c, tp); 4016940Ssam } 4026940Ssam } 4036940Ssam 4046940Ssam /* 4056940Ssam * Ioctl for DMF32. 4066940Ssam */ 4076940Ssam /*ARGSUSED*/ 4087630Ssam dmfioctl(dev, cmd, data, flag) 4096940Ssam dev_t dev; 4107630Ssam caddr_t data; 4116940Ssam { 4126940Ssam register struct tty *tp; 4136940Ssam register int unit = minor(dev); 4148567Sroot int error; 4156940Ssam 416*26312Skarels if (unit & 0200) 41721955Sbloom return (ENOTTY); 4186940Ssam tp = &dmf_tty[unit]; 4198567Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 4208567Sroot if (error >= 0) 4218567Sroot return (error); 4228567Sroot error = ttioctl(tp, cmd, data, flag); 4238567Sroot if (error >= 0) { 42417562Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 42517562Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 4266940Ssam dmfparam(unit); 4278567Sroot return (error); 4288567Sroot } 4298567Sroot switch (cmd) { 4306940Ssam 4316940Ssam case TIOCSBRK: 4328702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIS); 4336940Ssam break; 4347630Ssam 4356940Ssam case TIOCCBRK: 4368702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIC); 4376940Ssam break; 4387630Ssam 4396940Ssam case TIOCSDTR: 4408702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS); 4416940Ssam break; 4427630Ssam 4436940Ssam case TIOCCDTR: 4448702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC); 4456940Ssam break; 4467630Ssam 4476940Ssam case TIOCMSET: 4488702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET); 4496940Ssam break; 4507630Ssam 4516940Ssam case TIOCMBIS: 4528702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS); 4536940Ssam break; 4547630Ssam 4556940Ssam case TIOCMBIC: 4568702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC); 4576940Ssam break; 4587630Ssam 4596940Ssam case TIOCMGET: 4607630Ssam *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET)); 4616940Ssam break; 4627630Ssam 4636940Ssam default: 4648567Sroot return (ENOTTY); 4656940Ssam } 4668567Sroot return (0); 4676940Ssam } 4686940Ssam 4696940Ssam dmtodmf(bits) 4706940Ssam register int bits; 4716940Ssam { 4726940Ssam register int b; 4736940Ssam 4746940Ssam b = bits & 012; 4756940Ssam if (bits & DML_ST) b |= DMF_RATE; 4766940Ssam if (bits & DML_RTS) b |= DMF_RTS; 4776940Ssam if (bits & DML_USR) b |= DMF_USRW; 4786940Ssam return(b); 4796940Ssam } 4806940Ssam 4816940Ssam dmftodm(bits) 4826940Ssam register int bits; 4836940Ssam { 4846940Ssam register int b; 4856940Ssam 4866940Ssam b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE; 4876940Ssam if (bits & DMF_USRR) b |= DML_USR; 4886940Ssam if (bits & DMF_RTS) b |= DML_RTS; 4896940Ssam return(b); 4906940Ssam } 4916940Ssam 4926940Ssam 4936940Ssam /* 4946940Ssam * Set parameters from open or stty into the DMF hardware 4956940Ssam * registers. 4966940Ssam */ 4976940Ssam dmfparam(unit) 4986940Ssam register int unit; 4996940Ssam { 5006940Ssam register struct tty *tp; 5016940Ssam register struct dmfdevice *addr; 5026940Ssam register int lpar, lcr; 5036940Ssam int s; 5046940Ssam 5056940Ssam tp = &dmf_tty[unit]; 5066940Ssam addr = (struct dmfdevice *)tp->t_addr; 5076940Ssam /* 5086940Ssam * Block interrupts so parameters will be set 5096940Ssam * before the line interrupts. 5106940Ssam */ 51121955Sbloom s = spltty(); 5126940Ssam addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE; 5136940Ssam if ((tp->t_ispeed)==0) { 5146971Ssam tp->t_state |= TS_HUPCLS; 5158702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 51625449Skarels splx(s); 5176940Ssam return; 5186940Ssam } 5196940Ssam lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8); 5206940Ssam lcr = DMFLCR_ENA; 5216940Ssam if ((tp->t_ispeed) == B134) 5226940Ssam lpar |= BITS6|PENABLE; 52324270Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 5246940Ssam lpar |= BITS8; 5256940Ssam else { 5266940Ssam lpar |= BITS7|PENABLE; 5276940Ssam /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ 5286940Ssam } 52912450Ssam if (tp->t_flags&EVENP) 53012450Ssam lpar |= EPAR; 5316940Ssam if ((tp->t_ospeed) == B110) 5326940Ssam lpar |= TWOSB; 5336940Ssam lpar |= (unit&07); 5346940Ssam addr->dmflpr = lpar; 53525654Skarels addr->dmflctms = (addr->dmflctms &~ 0xff) | lcr; 5366940Ssam splx(s); 5376940Ssam } 5386940Ssam 5396940Ssam /* 5406940Ssam * DMF32 transmitter interrupt. 5416940Ssam * Restart the idle line. 5426940Ssam */ 5436940Ssam dmfxint(dmf) 5446940Ssam int dmf; 5456940Ssam { 546*26312Skarels int unit0 = dmf * 8; 547*26312Skarels struct tty *tp0 = &dmf_tty[unit0]; 5486940Ssam register struct tty *tp; 5496940Ssam register struct dmfdevice *addr; 5506940Ssam register struct uba_device *ui; 55121955Sbloom register int t; 5526940Ssam short cntr; 5536940Ssam 5546940Ssam ui = dmfinfo[dmf]; 5556940Ssam addr = (struct dmfdevice *)ui->ui_addr; 5566940Ssam while ((t = addr->dmfcsr) & DMF_TI) { 55721955Sbloom if (t & DMF_NXM) 55821955Sbloom /* SHOULD RESTART OR SOMETHING... */ 55921955Sbloom printf("dmf%d: NXM line %d\n", dmf, t >> 8 & 7); 56021955Sbloom t = t >> 8 & 7; 56121955Sbloom tp = tp0 + t; 5626971Ssam tp->t_state &= ~TS_BUSY; 5636971Ssam if (tp->t_state&TS_FLUSH) 5646971Ssam tp->t_state &= ~TS_FLUSH; 565*26312Skarels else if (dmf_dma[unit0 + t]) { 56621955Sbloom /* 56721955Sbloom * Do arithmetic in a short to make up 56821955Sbloom * for lost 16&17 bits. 56921955Sbloom */ 57021955Sbloom addr->dmfcsr = DMFIR_TBA | DMF_IE | t; 57121955Sbloom cntr = addr->dmftba - 57221955Sbloom UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 57321955Sbloom ndflush(&tp->t_outq, (int)cntr); 5746940Ssam } 5756940Ssam if (tp->t_line) 5766940Ssam (*linesw[tp->t_line].l_start)(tp); 5776940Ssam else 5786940Ssam dmfstart(tp); 5796940Ssam } 5806940Ssam } 5816940Ssam 5826940Ssam /* 5836940Ssam * Start (restart) transmission on the given DMF32 line. 5846940Ssam */ 5856940Ssam dmfstart(tp) 5866940Ssam register struct tty *tp; 5876940Ssam { 5886940Ssam register struct dmfdevice *addr; 5898607Sroot register int unit, nch; 5906940Ssam int s; 59121955Sbloom register int dmf; 5926940Ssam 5936940Ssam unit = minor(tp->t_dev); 59421955Sbloom dmf = unit >> 3; 5956940Ssam unit &= 07; 5966940Ssam addr = (struct dmfdevice *)tp->t_addr; 5976940Ssam 5986940Ssam /* 5996940Ssam * Must hold interrupts in following code to prevent 6006940Ssam * state of the tp from changing. 6016940Ssam */ 60221955Sbloom s = spltty(); 6036940Ssam /* 6046940Ssam * If it's currently active, or delaying, no need to do anything. 6056940Ssam */ 6066971Ssam if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 6076940Ssam goto out; 6086940Ssam /* 6096940Ssam * If there are still characters in the silo, 6106940Ssam * just reenable the transmitter. 6116940Ssam */ 6126940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6136940Ssam if (addr->dmftsc) { 6146940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 61525449Skarels addr->dmflctms = addr->dmflctms | DMF_TE; 6166971Ssam tp->t_state |= TS_BUSY; 6176940Ssam goto out; 6186940Ssam } 6196940Ssam /* 6206940Ssam * If there are sleepers, and output has drained below low 6216940Ssam * water mark, wake up the sleepers. 6226940Ssam */ 62321955Sbloom if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 62421955Sbloom if (tp->t_state&TS_ASLEEP) { 62521955Sbloom tp->t_state &= ~TS_ASLEEP; 62621955Sbloom wakeup((caddr_t)&tp->t_outq); 62721955Sbloom } 62821955Sbloom if (tp->t_wsel) { 62921955Sbloom selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 63021955Sbloom tp->t_wsel = 0; 63121955Sbloom tp->t_state &= ~TS_WCOLL; 63221955Sbloom } 6336940Ssam } 6346940Ssam /* 6356940Ssam * Now restart transmission unless the output queue is 6366940Ssam * empty. 6376940Ssam */ 6386940Ssam if (tp->t_outq.c_cc == 0) 6396940Ssam goto out; 6409550Ssam if (tp->t_flags & (RAW|LITOUT)) 6416940Ssam nch = ndqb(&tp->t_outq, 0); 6426940Ssam else { 64321955Sbloom if ((nch = ndqb(&tp->t_outq, 0200)) == 0) { 64421955Sbloom /* 64521955Sbloom * If first thing on queue is a delay process it. 64621955Sbloom */ 6476940Ssam nch = getc(&tp->t_outq); 6486940Ssam timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 6496971Ssam tp->t_state |= TS_TIMEOUT; 6506940Ssam goto out; 6516940Ssam } 6526940Ssam } 6536940Ssam /* 6546940Ssam * If characters to transmit, restart transmission. 6556940Ssam */ 65621955Sbloom if (nch >= dmf_mindma) { 65721955Sbloom register car; 65821955Sbloom 65921955Sbloom dmf_dma[minor(tp->t_dev)] = 1; 6606940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 66125449Skarels addr->dmflctms = addr->dmflctms | DMF_TE; 6626940Ssam car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); 6636940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; 6646940Ssam addr->dmftba = car; 66521955Sbloom addr->dmftcc = ((car >> 2) & 0xc000) | nch; 66621955Sbloom tp->t_state |= TS_BUSY; 66721955Sbloom } else if (nch) { 6686940Ssam register char *cp = tp->t_outq.c_cf; 6696940Ssam register int i; 6706940Ssam 67121955Sbloom dmf_dma[minor(tp->t_dev)] = 0; 6726940Ssam nch = MIN(nch, DMF_SILOCNT); 6736940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 67425449Skarels addr->dmflctms = addr->dmflctms | DMF_TE; 6756940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6766940Ssam for (i = 0; i < nch; i++) 6776940Ssam addr->dmftbuf = *cp++; 6786940Ssam ndflush(&tp->t_outq, nch); 6796971Ssam tp->t_state |= TS_BUSY; 6806940Ssam } 6816940Ssam out: 6826940Ssam splx(s); 6836940Ssam } 6846940Ssam 6856940Ssam /* 6866940Ssam * Stop output on a line, e.g. for ^S/^Q or output flush. 6876940Ssam */ 6886940Ssam /*ARGSUSED*/ 6896940Ssam dmfstop(tp, flag) 6906940Ssam register struct tty *tp; 6916940Ssam { 6926940Ssam register struct dmfdevice *addr; 69321955Sbloom register unit = minor(tp->t_dev) & 7; 69421955Sbloom int s; 6956940Ssam 6966940Ssam addr = (struct dmfdevice *)tp->t_addr; 6976940Ssam /* 6986940Ssam * Block input/output interrupts while messing with state. 6996940Ssam */ 70021955Sbloom s = spltty(); 70121955Sbloom if (flag) { 70221955Sbloom addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 70321955Sbloom if (addr->dmftsc) { 70421955Sbloom /* 70521955Sbloom * Flush regardless of whether we're transmitting 70621955Sbloom * (TS_BUSY), if the silo contains untransmitted 70721955Sbloom * characters. 70821955Sbloom */ 70921955Sbloom addr->dmfcsr = DMFIR_LCR | unit | DMF_IE; 71025449Skarels addr->dmflctms = addr->dmflctms | DMF_TE | DMF_FLUSH; 71121955Sbloom /* this will interrupt so let dmfxint handle the rest */ 71221955Sbloom tp->t_state |= TS_FLUSH|TS_BUSY; 71321955Sbloom } 71421955Sbloom } else { 71521955Sbloom if (tp->t_state & TS_BUSY) { 71621955Sbloom /* 71721955Sbloom * Stop transmission by disabling 71821955Sbloom * the transmitter. We'll pick up where we 71921955Sbloom * left off by reenabling in dmfstart. 72021955Sbloom */ 72121955Sbloom addr->dmfcsr = DMFIR_LCR | unit | DMF_IE; 72225449Skarels addr->dmflctms = addr->dmflctms &~ DMF_TE; 72321955Sbloom /* no interrupt here */ 7246971Ssam tp->t_state &= ~TS_BUSY; 72521955Sbloom } 7266940Ssam } 7276940Ssam splx(s); 7286940Ssam } 7296940Ssam 7306940Ssam /* 7316940Ssam * DMF32 modem control 7326940Ssam */ 7336940Ssam dmfmctl(dev, bits, how) 7346940Ssam dev_t dev; 7356940Ssam int bits, how; 7366940Ssam { 7376940Ssam register struct dmfdevice *dmfaddr; 7386940Ssam register int unit, mbits, lcr; 7396940Ssam int s; 7406940Ssam 7416940Ssam unit = minor(dev); 7426940Ssam dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr); 7436940Ssam unit &= 07; 74421955Sbloom s = spltty(); 7456940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 7466940Ssam mbits = dmfaddr->dmfrms << 8; 7476940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 74825654Skarels lcr = dmfaddr->dmflctms; 74925449Skarels mbits |= (lcr & 0xff00) >> 8; 7506940Ssam switch (how) { 7516940Ssam case DMSET: 75212449Ssam mbits = (mbits &0xff00) | bits; 7536940Ssam break; 7546940Ssam 7556940Ssam case DMBIS: 7566940Ssam mbits |= bits; 7576940Ssam break; 7586940Ssam 7596940Ssam case DMBIC: 7606940Ssam mbits &= ~bits; 7616940Ssam break; 7626940Ssam 7636940Ssam case DMGET: 7646940Ssam (void) splx(s); 7656940Ssam return(mbits); 7666940Ssam } 7676940Ssam if (mbits & DMF_BRK) 7686940Ssam lcr |= DMF_RBRK; 7696940Ssam else 7706940Ssam lcr &= ~DMF_RBRK; 77125449Skarels dmfaddr->dmflctms = ((mbits & 037) << 8) | (lcr & 0xff); 7726940Ssam (void) splx(s); 7736940Ssam return(mbits); 7746940Ssam } 7756940Ssam 7766940Ssam /* 7776940Ssam * Reset state of driver if UBA reset was necessary. 7786940Ssam * Reset the csr, lpr, and lcr registers on open lines, and 7796940Ssam * restart transmitters. 7806940Ssam */ 7816940Ssam dmfreset(uban) 7826940Ssam int uban; 7836940Ssam { 7846940Ssam register int dmf, unit; 7856940Ssam register struct tty *tp; 7866940Ssam register struct uba_device *ui; 7876940Ssam register struct dmfdevice *addr; 7886940Ssam int i; 7896940Ssam 7906940Ssam for (dmf = 0; dmf < NDMF; dmf++) { 7916940Ssam ui = dmfinfo[dmf]; 7926940Ssam if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 7936940Ssam continue; 7946940Ssam printf(" dmf%d", dmf); 79526221Skarels if (dmf_ubinfo[uban]) { 79625449Skarels dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 79725449Skarels nclist*sizeof (struct cblock), 0); 79826221Skarels cbase[uban] = UBAI_ADDR(dmf_ubinfo[uban]); 79925449Skarels } 8006940Ssam addr = (struct dmfdevice *)ui->ui_addr; 8016940Ssam addr->dmfcsr = DMF_IE; 80221955Sbloom addr->dmfrsp = dmf_timeout; 8036940Ssam unit = dmf * 8; 8046940Ssam for (i = 0; i < 8; i++) { 8056940Ssam tp = &dmf_tty[unit]; 8066971Ssam if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 8076940Ssam dmfparam(unit); 8088702Sroot (void) dmfmctl(unit, DMF_ON, DMSET); 8096971Ssam tp->t_state &= ~TS_BUSY; 8106940Ssam dmfstart(tp); 8116940Ssam } 8126940Ssam unit++; 8136940Ssam } 8146940Ssam } 8156940Ssam } 8166940Ssam 817*26312Skarels /* 818*26312Skarels * dmflopen -- open the line printer port on a dmf32 81921955Sbloom */ 820*26312Skarels /* ARGSUSED */ 821*26312Skarels dmflopen(dev, flag) 822*26312Skarels dev_t dev; 823*26312Skarels int flag; 82421955Sbloom { 82521955Sbloom register int dmf; 82621955Sbloom register struct dmfl_softc *sc; 82721955Sbloom register struct uba_device *ui; 82821955Sbloom register struct dmfdevice *addr; 82921955Sbloom 830*26312Skarels dmf = DMFL_UNIT(dev); 831*26312Skarels if (((sc= &dmfl_softc[dmf])->dmfl_state & OPEN) || 83221955Sbloom ((ui=dmfinfo[dmf]) == 0) || ui->ui_alive == 0) 83321955Sbloom return(ENXIO); 83421955Sbloom addr = (struct dmfdevice *)ui->ui_addr; 835*26312Skarels if ((addr->dmfl[0] & DMFL_OFFLINE)) { 83621955Sbloom /*printf("dmf: line printer offline/jammed\n");*/ 837*26312Skarels return (EIO); 83821955Sbloom } 839*26312Skarels if ((addr->dmfl[0] & DMFL_CONV)) { 84021955Sbloom printf("dmf:line printer disconnected\n"); 841*26312Skarels return (EIO); 84221955Sbloom } 84321955Sbloom 84421955Sbloom addr->dmfl[0] = 0; 84521955Sbloom sc->dmfl_state |= OPEN; 846*26312Skarels return (0); 84721955Sbloom } 84821955Sbloom 849*26312Skarels /* ARGSUSED */ 850*26312Skarels dmflclose(dev, flag) 851*26312Skarels dev_t dev; 852*26312Skarels int flag; 85321955Sbloom { 85421955Sbloom register int dmf= DMFL_UNIT(dev); 85521955Sbloom register struct dmfl_softc *sc = &dmfl_softc[dmf]; 85621955Sbloom 857*26312Skarels dmflout(dev, "\f", 1); 85821955Sbloom sc->dmfl_state = 0; 859*26312Skarels if (sc->dmfl_info != 0) 86021955Sbloom ubarelse((struct dmfdevice *)(dmfinfo[dmf])->ui_ubanum, 86121955Sbloom &(sc->dmfl_info)); 86221955Sbloom 863*26312Skarels ((struct dmfdevice *)(dmfinfo[dmf]->ui_addr))->dmfl[0] = 0; 864*26312Skarels return (0); 86521955Sbloom } 86621955Sbloom 867*26312Skarels dmflwrite(dev, uio) 868*26312Skarels dev_t dev; 869*26312Skarels struct uio *uio; 87021955Sbloom { 87121955Sbloom register unsigned int n; 87221955Sbloom register int error; 87321955Sbloom register struct dmfl_softc *sc; 87421955Sbloom 87521955Sbloom sc = &dmfl_softc[DMFL_UNIT(dev)]; 876*26312Skarels if (sc->dmfl_state&ERROR) 877*26312Skarels return(EIO); 878*26312Skarels while (n = min(DMFL_BUFSIZ, (unsigned)uio->uio_resid)) { 879*26312Skarels if (error = uiomove(&sc->dmfl_buf[0], (int)n, UIO_WRITE, uio)) { 88021955Sbloom printf("uio move error\n"); 881*26312Skarels return (error); 88221955Sbloom } 883*26312Skarels if (error = dmflout(dev, &sc->dmfl_buf[0], n)) 884*26312Skarels return (error); 88521955Sbloom } 886*26312Skarels return (0); 88721955Sbloom } 88821955Sbloom 88921955Sbloom 890*26312Skarels /* 891*26312Skarels * dmflout -- start io operation to dmf line printer 89221955Sbloom * cp is addr of buf of n chars to be sent. 89321955Sbloom * 89421955Sbloom * -- dmf will be put in formatted output mode, this will 89521955Sbloom * be selectable from an ioctl if the 89621955Sbloom * need ever arises. 89721955Sbloom */ 898*26312Skarels dmflout(dev, cp, n) 899*26312Skarels dev_t dev; 900*26312Skarels char *cp; 901*26312Skarels int n; 90221955Sbloom { 90321955Sbloom register struct dmfl_softc *sc; 90421955Sbloom register int dmf; 90521955Sbloom register struct uba_device *ui; 90621955Sbloom register struct dmfdevice *d; 90721955Sbloom register unsigned info; 90821955Sbloom register unsigned i; 90921955Sbloom 910*26312Skarels dmf = DMFL_UNIT(dev); 911*26312Skarels sc = &dmfl_softc[dmf]; 912*26312Skarels if (sc->dmfl_state & ERROR) 913*26312Skarels return (EIO); 914*26312Skarels ui = dmfinfo[dmf]; 915*26312Skarels /* 916*26312Skarels * allocate unibus resources, will be released when io 917*26312Skarels * operation is done. 91821955Sbloom */ 919*26312Skarels sc->dmfl_info = info = uballoc(ui->ui_ubanum,cp,n,0); 920*26312Skarels d = (struct dmfdevice *)ui->ui_addr; 921*26312Skarels d->dmfl[0] = (2<<8) | DMFL_FORMAT; /* indir reg 2 */ 92221955Sbloom /* indir reg auto increments on r/w */ 92321955Sbloom /* SO DON'T CHANGE THE ORDER OF THIS CODE */ 924*26312Skarels d->dmfl[1] = 0; /* prefix chars & num */ 925*26312Skarels d->dmfl[1] = 0; /* suffix chars & num */ 926*26312Skarels d->dmfl[1] = info; /* dma lo 16 bits addr */ 92721955Sbloom 92821955Sbloom /* NOT DOCUMENTED !! */ 92921955Sbloom d->dmfl[1] = -n; /* number of chars */ 93021955Sbloom /* ----------^-------- */ 93121955Sbloom 93221955Sbloom d->dmfl[1] = ((info>>16)&3) /* dma hi 2 bits addr */ 93321955Sbloom | (1<<8) /* auto cr insert */ 93421955Sbloom | (1<<9) /* use real ff */ 93521955Sbloom | (1<<15); /* no u/l conversion */ 93621955Sbloom d->dmfl[1] = sc->dmfl_lines /* lines per page */ 93721955Sbloom | (sc->dmfl_cols<<8); /* carriage width */ 93821955Sbloom sc->dmfl_state |= ASLP; 939*26312Skarels i = spltty(); 94021955Sbloom d->dmfl[0] |= DMFL_PEN|DMFL_IE; 941*26312Skarels while (sc->dmfl_state & ASLP) { 942*26312Skarels sleep(&sc->dmfl_buf[0], (PZERO+8)); 943*26312Skarels while (sc->dmfl_state & ERROR) { 944*26312Skarels timeout(dmflint, dmf, 10*hz); 945*26312Skarels sleep(&sc->dmfl_state, (PZERO+8)); 94621955Sbloom } 947*26312Skarels /*if (sc->dmfl_state&ERROR) return (EIO);*/ 94821955Sbloom } 94921955Sbloom splx(i); 950*26312Skarels return (0); 95121955Sbloom } 952*26312Skarels 953*26312Skarels /* 954*26312Skarels * dmflint -- handle an interrupt from the line printer part of the dmf32 95521955Sbloom */ 95621955Sbloom dmflint(dmf) 957*26312Skarels int dmf; 95821955Sbloom { 95921955Sbloom register struct uba_device *ui; 96021955Sbloom register struct dmfl_softc *sc; 96121955Sbloom register struct dmfdevice *d; 96221955Sbloom 963*26312Skarels ui = dmfinfo[dmf]; 964*26312Skarels sc = &dmfl_softc[dmf]; 965*26312Skarels d = (struct dmfdevice *)ui->ui_addr; 96621955Sbloom 96721955Sbloom d->dmfl[0] &= ~DMFL_IE; 96821955Sbloom 969*26312Skarels if (sc->dmfl_state & ERROR) { 97021955Sbloom printf("dmfl: intr while in error state \n"); 971*26312Skarels if ((d->dmfl[0]&DMFL_OFFLINE) == 0) 97221955Sbloom sc->dmfl_state &= ~ERROR; 97321955Sbloom wakeup(&sc->dmfl_state); 97421955Sbloom return; 97521955Sbloom } 976*26312Skarels if (d->dmfl[0] & DMFL_DMAERR) 97721955Sbloom printf("dmf:NXM\n"); 978*26312Skarels if (d->dmfl[0] & DMFL_OFFLINE) { 97921955Sbloom printf("dmf:printer error\n"); 98021955Sbloom sc->dmfl_state |= ERROR; 98121955Sbloom } 982*26312Skarels if (d->dmfl[0] & DMFL_PDONE) { 98321955Sbloom #ifdef notdef 984*26312Skarels printf("bytes= %d\n", d->dmfl[1]); 985*26312Skarels printf("lines= %d\n", d->dmfl[1]); 98621955Sbloom #endif 98721955Sbloom } 98821955Sbloom sc->dmfl_state &= ~ASLP; 98921955Sbloom wakeup(&sc->dmfl_buf[0]); 990*26312Skarels if (sc->dmfl_info != 0) 991*26312Skarels ubarelse(ui->ui_ubanum, &sc->dmfl_info); 99221955Sbloom sc->dmfl_info = 0; 99321955Sbloom } 99421955Sbloom 9956940Ssam /* stubs for interrupt routines for devices not yet supported */ 9966940Ssam 997*26312Skarels dmfsrint() 998*26312Skarels { 999*26312Skarels printf("dmfsrint\n"); 1000*26312Skarels } 10016940Ssam 1002*26312Skarels dmfsxint() 1003*26312Skarels { 1004*26312Skarels printf("dmfsxint\n"); 1005*26312Skarels } 10066940Ssam 1007*26312Skarels dmfdaint() 1008*26312Skarels { 1009*26312Skarels printf("dmfdaint\n"); 1010*26312Skarels } 10116940Ssam 1012*26312Skarels dmfdbint() 1013*26312Skarels { 1014*26312Skarels printf("dmfdbint\n"); 1015*26312Skarels } 10166940Ssam #endif 1017