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*25449Skarels * @(#)dmf.c 6.11 (Berkeley) 11/08/85 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 69*25449Skarels 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 78*25449Skarels #ifndef PORTSELECTOR 79*25449Skarels #define ISPEED B9600 80*25449Skarels #define IFLAGS (EVENP|ODDP|ECHO) 81*25449Skarels #else 82*25449Skarels #define ISPEED B4800 83*25449Skarels #define IFLAGS (EVENP|ODDP) 84*25449Skarels #endif 85*25449Skarels 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 */ 120*25449Skarels 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; 139*25449Skarels 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); 154*25449Skarels 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) { 159*25449Skarels /* Async portion only */ 160*25449Skarels 161*25449Skarels cvec = (uba_hd[numuba].uh_lastiv -= 8); 162*25449Skarels dmfaddr->dmfccsr0 = (cvec - 2*8) >> 2; 163*25449Skarels intrv[0] = ctlr->ui_intr[4]; 164*25449Skarels intrv[1] = ctlr->ui_intr[5]; 165*25449Skarels ctlr->ui_intr = intrv; 16621955Sbloom } 16721955Sbloom else if (dmfoptions == DMFC_LP) { 168*25449Skarels /* LP portion only */ 16921955Sbloom 170*25449Skarels cvec = (uba_hd[numuba].uh_lastiv -= 8); 171*25449Skarels ctlr->ui_intr = &ctlr->ui_intr[6]; 17221955Sbloom } 173*25449Skarels else if (dmfoptions == (DMFC_LP|DMFC_ASYNC)) { 174*25449Skarels /* LP ans Async portions only */ 175*25449Skarels 176*25449Skarels cvec = (uba_hd[numuba].uh_lastiv -= 2*8); 177*25449Skarels ctlr->ui_intr = &ctlr->ui_intr[4]; 178*25449Skarels } 17921955Sbloom else { 180*25449Skarels /* All other configurations get everything */ 18121955Sbloom 18221955Sbloom cvec = (uba_hd[numuba].uh_lastiv -= 4*8); 18321955Sbloom } 184*25449Skarels a = (dmfoptions >> 12) & 0xf; 185*25449Skarels printf("dmf%d:", ctlr->ui_unit); 186*25449Skarels for(i=0;a != 0;++i,a >>= 1) { 187*25449Skarels if(a&1) 188*25449Skarels printf(" %s",dmfdevs[i]); 189*25449Skarels } 190*25449Skarels printf(".\n"); 19121955Sbloom 19221955Sbloom if (dmfoptions & DMFC_LP) 19321955Sbloom dmfaddr->dmfl[0] = DMFL_RESET; 1946940Ssam /* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */ 1957412Skre return (sizeof (struct dmfdevice)); 1966940Ssam } 1976940Ssam 1986940Ssam /* 1996940Ssam * Routine called to attach a dmf. 2006940Ssam */ 2016940Ssam dmfattach(ui) 2026940Ssam struct uba_device *ui; 2036940Ssam { 20421955Sbloom register int cols = (ui->ui_flags>>8) & 0xff; 20521955Sbloom register int lines = (ui->ui_flags>>16) & 0xff; 2066940Ssam 20721955Sbloom dmfsoftCAR[ui->ui_unit] = ui->ui_flags & 0xff; 20821955Sbloom dmfl_softc[ui->ui_unit].dmfl_cols = cols==0?DMFL_DEFCOLS:cols; 20921955Sbloom dmfl_softc[ui->ui_unit].dmfl_lines = lines==0?DMFL_DEFLINES:lines; 2106940Ssam } 2116940Ssam 2126940Ssam 2136940Ssam /* 2146940Ssam * Open a DMF32 line, mapping the clist onto the uba if this 2156940Ssam * is the first dmf on this uba. Turn on this dmf if this is 2166940Ssam * the first use of it. 2176940Ssam */ 2186940Ssam /*ARGSUSED*/ 2196940Ssam dmfopen(dev, flag) 2206940Ssam dev_t dev; 2216940Ssam { 2226940Ssam register struct tty *tp; 2236940Ssam register int unit, dmf; 2246940Ssam register struct dmfdevice *addr; 2256940Ssam register struct uba_device *ui; 2266940Ssam int s; 2276940Ssam 2286940Ssam unit = minor(dev); 22921955Sbloom if(unit & 0200) 23021955Sbloom return(dmflopen(dev,flag)); 2316940Ssam dmf = unit >> 3; 2328567Sroot if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) 2338567Sroot return (ENXIO); 2346940Ssam tp = &dmf_tty[unit]; 2358567Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2368567Sroot return (EBUSY); 2376940Ssam addr = (struct dmfdevice *)ui->ui_addr; 2386940Ssam tp->t_addr = (caddr_t)addr; 2396940Ssam tp->t_oproc = dmfstart; 2406971Ssam tp->t_state |= TS_WOPEN; 2416940Ssam /* 2426940Ssam * While setting up state for this uba and this dmf, 2436940Ssam * block uba resets which can clear the state. 2446940Ssam */ 24521955Sbloom s = spltty(); 246*25449Skarels if (cbase[ui->ui_ubanum] == 0) { 2476940Ssam dmf_ubinfo[ui->ui_ubanum] = 2486940Ssam uballoc(ui->ui_ubanum, (caddr_t)cfree, 2496940Ssam nclist*sizeof(struct cblock), 0); 2506940Ssam cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff; 2516940Ssam } 2526940Ssam if ((dmfact&(1<<dmf)) == 0) { 2536940Ssam addr->dmfcsr |= DMF_IE; 2546940Ssam dmfact |= (1<<dmf); 25521955Sbloom addr->dmfrsp = dmf_timeout; 2566940Ssam } 2576940Ssam splx(s); 2586940Ssam /* 2596940Ssam * If this is first open, initialze tty state to default. 2606940Ssam */ 2616971Ssam if ((tp->t_state&TS_ISOPEN) == 0) { 2626940Ssam ttychars(tp); 263*25449Skarels tp->t_ispeed = ISPEED; 264*25449Skarels tp->t_ospeed = ISPEED; 265*25449Skarels tp->t_flags = IFLAGS; 2666940Ssam dmfparam(unit); 2676940Ssam } 2686940Ssam /* 2696940Ssam * Wait for carrier, then process line discipline specific open. 2706940Ssam */ 2716940Ssam if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) || 2726940Ssam (dmfsoftCAR[dmf] & (1<<(unit&07)))) 2736971Ssam tp->t_state |= TS_CARR_ON; 27421955Sbloom s = spltty(); 2756971Ssam while ((tp->t_state & TS_CARR_ON) == 0) { 2766971Ssam tp->t_state |= TS_WOPEN; 2776940Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 2786940Ssam } 2796940Ssam splx(s); 2808567Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 2816940Ssam } 2826940Ssam 2836940Ssam /* 2846940Ssam * Close a DMF32 line. 2856940Ssam */ 2866940Ssam /*ARGSUSED*/ 2876940Ssam dmfclose(dev, flag) 2886940Ssam dev_t dev; 2896940Ssam int flag; 2906940Ssam { 2916940Ssam register struct tty *tp; 2926940Ssam register unit; 2936940Ssam 2946940Ssam unit = minor(dev); 29521955Sbloom if(unit & 0200) 29621955Sbloom return(dmflclose(dev,flag)); 29721955Sbloom 2986940Ssam tp = &dmf_tty[unit]; 2996940Ssam (*linesw[tp->t_line].l_close)(tp); 3008702Sroot (void) dmfmctl(unit, DMF_BRK, DMBIC); 3016971Ssam if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3028702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 3036940Ssam ttyclose(tp); 3046940Ssam } 3056940Ssam 3067726Sroot dmfread(dev, uio) 3076940Ssam dev_t dev; 3087726Sroot struct uio *uio; 3096940Ssam { 3106940Ssam register struct tty *tp; 3116940Ssam 31221955Sbloom if(minor(dev)&0200) 31321955Sbloom return(ENXIO); 3146940Ssam tp = &dmf_tty[minor(dev)]; 3157726Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 3166940Ssam } 3176940Ssam 3187832Sroot dmfwrite(dev, uio) 3196940Ssam dev_t dev; 3207832Sroot struct uio *uio; 3216940Ssam { 3226940Ssam register struct tty *tp; 3236940Ssam 32421955Sbloom if(minor(dev)&0200) 32521955Sbloom return(dmflwrite(dev,uio)); 3266940Ssam tp = &dmf_tty[minor(dev)]; 3278530Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 3286940Ssam } 3296940Ssam 3306940Ssam /* 3316940Ssam * DMF32 receiver interrupt. 3326940Ssam */ 3336940Ssam dmfrint(dmf) 3346940Ssam int dmf; 3356940Ssam { 3366940Ssam register c; 3376940Ssam register struct dmfdevice *addr; 3386940Ssam register struct tty *tp0; 33921955Sbloom register dev; 34021955Sbloom int unit; 341*25449Skarels int overrun = 0; 3426940Ssam 34321955Sbloom { 34421955Sbloom register struct uba_device *ui; 34521955Sbloom 34621955Sbloom ui = dmfinfo[dmf]; 34721955Sbloom if (ui == 0 || ui->ui_alive == 0) 34821955Sbloom return; 34921955Sbloom addr = (struct dmfdevice *)ui->ui_addr; 35021955Sbloom } 35121955Sbloom tp0 = &dmf_tty[dmf * 8]; 3526940Ssam /* 3536940Ssam * Loop fetching characters from the silo for this 3546940Ssam * dmf until there are no more in the silo. 3556940Ssam */ 3566940Ssam while ((c = addr->dmfrbuf) < 0) { 35721955Sbloom register struct tty *tp; 35821955Sbloom 35921955Sbloom unit = (c >> 8) & 07; 36021955Sbloom tp = tp0 + unit; 36121955Sbloom dev = unit + dmf * 8; 3626940Ssam if (c & DMF_DSC) { 36321955Sbloom addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 364*25449Skarels if (addr->dmfrms & DMF_CAR) 365*25449Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 366*25449Skarels else if ((dmfsoftCAR[dmf] & (1<<unit)) == 0 && 367*25449Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 368*25449Skarels addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 369*25449Skarels addr->dmflctms = DMFLCR_ENA; 3706940Ssam } 3716940Ssam continue; 3726940Ssam } 3736971Ssam if ((tp->t_state&TS_ISOPEN)==0) { 374*25449Skarels wakeup((caddr_t)&tp->t_rawq); 375*25449Skarels #ifdef PORTSELECTOR 376*25449Skarels if ((tp->t_state&TS_WOPEN) == 0) 377*25449Skarels #endif 378*25449Skarels continue; 3796940Ssam } 38021956Sbloom if (c & (DMF_PE|DMF_DO|DMF_FE)) { 38121955Sbloom if (c & DMF_PE) 38221955Sbloom if ((tp->t_flags&(EVENP|ODDP))==EVENP 38321955Sbloom || (tp->t_flags&(EVENP|ODDP))==ODDP ) 38421955Sbloom continue; 38521955Sbloom if ((c & DMF_DO) && overrun == 0) { 38624842Seric log(LOG_WARNING, "dmf%d: silo overflow\n", dmf); 38721955Sbloom overrun = 1; 38821955Sbloom } 38921955Sbloom if (c & DMF_FE) 39021955Sbloom /* 39121955Sbloom * At framing error (break) generate 39221955Sbloom * a null (in raw mode, for getty), or a 39321955Sbloom * interrupt (in cooked/cbreak mode). 39421955Sbloom */ 39521955Sbloom if (tp->t_flags&RAW) 39621955Sbloom c = 0; 39721955Sbloom else 39821955Sbloom c = tp->t_intrc; 3996940Ssam } 4006940Ssam #if NBK > 0 4016940Ssam if (tp->t_line == NETLDISC) { 4026940Ssam c &= 0177; 4036940Ssam BKINPUT(c, tp); 4046940Ssam } else 4056940Ssam #endif 4066940Ssam (*linesw[tp->t_line].l_rint)(c, tp); 4076940Ssam } 4086940Ssam } 4096940Ssam 4106940Ssam /* 4116940Ssam * Ioctl for DMF32. 4126940Ssam */ 4136940Ssam /*ARGSUSED*/ 4147630Ssam dmfioctl(dev, cmd, data, flag) 4156940Ssam dev_t dev; 4167630Ssam caddr_t data; 4176940Ssam { 4186940Ssam register struct tty *tp; 4196940Ssam register int unit = minor(dev); 4208567Sroot int error; 4216940Ssam 42221955Sbloom if(unit & 0200) 42321955Sbloom return (ENOTTY); 4246940Ssam tp = &dmf_tty[unit]; 4258567Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 4268567Sroot if (error >= 0) 4278567Sroot return (error); 4288567Sroot error = ttioctl(tp, cmd, data, flag); 4298567Sroot if (error >= 0) { 43017562Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 43117562Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 4326940Ssam dmfparam(unit); 4338567Sroot return (error); 4348567Sroot } 4358567Sroot switch (cmd) { 4366940Ssam 4376940Ssam case TIOCSBRK: 4388702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIS); 4396940Ssam break; 4407630Ssam 4416940Ssam case TIOCCBRK: 4428702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIC); 4436940Ssam break; 4447630Ssam 4456940Ssam case TIOCSDTR: 4468702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS); 4476940Ssam break; 4487630Ssam 4496940Ssam case TIOCCDTR: 4508702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC); 4516940Ssam break; 4527630Ssam 4536940Ssam case TIOCMSET: 4548702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET); 4556940Ssam break; 4567630Ssam 4576940Ssam case TIOCMBIS: 4588702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS); 4596940Ssam break; 4607630Ssam 4616940Ssam case TIOCMBIC: 4628702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC); 4636940Ssam break; 4647630Ssam 4656940Ssam case TIOCMGET: 4667630Ssam *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET)); 4676940Ssam break; 4687630Ssam 4696940Ssam default: 4708567Sroot return (ENOTTY); 4716940Ssam } 4728567Sroot return (0); 4736940Ssam } 4746940Ssam 4756940Ssam dmtodmf(bits) 4766940Ssam register int bits; 4776940Ssam { 4786940Ssam register int b; 4796940Ssam 4806940Ssam b = bits & 012; 4816940Ssam if (bits & DML_ST) b |= DMF_RATE; 4826940Ssam if (bits & DML_RTS) b |= DMF_RTS; 4836940Ssam if (bits & DML_USR) b |= DMF_USRW; 4846940Ssam return(b); 4856940Ssam } 4866940Ssam 4876940Ssam dmftodm(bits) 4886940Ssam register int bits; 4896940Ssam { 4906940Ssam register int b; 4916940Ssam 4926940Ssam b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE; 4936940Ssam if (bits & DMF_USRR) b |= DML_USR; 4946940Ssam if (bits & DMF_RTS) b |= DML_RTS; 4956940Ssam return(b); 4966940Ssam } 4976940Ssam 4986940Ssam 4996940Ssam /* 5006940Ssam * Set parameters from open or stty into the DMF hardware 5016940Ssam * registers. 5026940Ssam */ 5036940Ssam dmfparam(unit) 5046940Ssam register int unit; 5056940Ssam { 5066940Ssam register struct tty *tp; 5076940Ssam register struct dmfdevice *addr; 5086940Ssam register int lpar, lcr; 5096940Ssam int s; 5106940Ssam 5116940Ssam tp = &dmf_tty[unit]; 5126940Ssam addr = (struct dmfdevice *)tp->t_addr; 5136940Ssam /* 5146940Ssam * Block interrupts so parameters will be set 5156940Ssam * before the line interrupts. 5166940Ssam */ 51721955Sbloom s = spltty(); 5186940Ssam addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE; 5196940Ssam if ((tp->t_ispeed)==0) { 5206971Ssam tp->t_state |= TS_HUPCLS; 5218702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 522*25449Skarels splx(s); 5236940Ssam return; 5246940Ssam } 5256940Ssam lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8); 5266940Ssam lcr = DMFLCR_ENA; 5276940Ssam if ((tp->t_ispeed) == B134) 5286940Ssam lpar |= BITS6|PENABLE; 52924270Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 5306940Ssam lpar |= BITS8; 5316940Ssam else { 5326940Ssam lpar |= BITS7|PENABLE; 5336940Ssam /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ 5346940Ssam } 53512450Ssam if (tp->t_flags&EVENP) 53612450Ssam lpar |= EPAR; 5376940Ssam if ((tp->t_ospeed) == B110) 5386940Ssam lpar |= TWOSB; 5396940Ssam lpar |= (unit&07); 5406940Ssam addr->dmflpr = lpar; 54112449Ssam SETLCR(addr, lcr); 5426940Ssam splx(s); 5436940Ssam } 5446940Ssam 5456940Ssam /* 5466940Ssam * DMF32 transmitter interrupt. 5476940Ssam * Restart the idle line. 5486940Ssam */ 5496940Ssam dmfxint(dmf) 5506940Ssam int dmf; 5516940Ssam { 55221955Sbloom int u = dmf * 8; 55321955Sbloom struct tty *tp0 = &dmf_tty[u]; 5546940Ssam register struct tty *tp; 5556940Ssam register struct dmfdevice *addr; 5566940Ssam register struct uba_device *ui; 55721955Sbloom register int t; 5586940Ssam short cntr; 5596940Ssam 5606940Ssam ui = dmfinfo[dmf]; 5616940Ssam addr = (struct dmfdevice *)ui->ui_addr; 5626940Ssam while ((t = addr->dmfcsr) & DMF_TI) { 56321955Sbloom if (t & DMF_NXM) 56421955Sbloom /* SHOULD RESTART OR SOMETHING... */ 56521955Sbloom printf("dmf%d: NXM line %d\n", dmf, t >> 8 & 7); 56621955Sbloom t = t >> 8 & 7; 56721955Sbloom tp = tp0 + t; 5686971Ssam tp->t_state &= ~TS_BUSY; 5696971Ssam if (tp->t_state&TS_FLUSH) 5706971Ssam tp->t_state &= ~TS_FLUSH; 57121955Sbloom else if (dmf_dma[u + t]) { 57221955Sbloom /* 57321955Sbloom * Do arithmetic in a short to make up 57421955Sbloom * for lost 16&17 bits. 57521955Sbloom */ 57621955Sbloom addr->dmfcsr = DMFIR_TBA | DMF_IE | t; 57721955Sbloom cntr = addr->dmftba - 57821955Sbloom UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 57921955Sbloom ndflush(&tp->t_outq, (int)cntr); 5806940Ssam } 5816940Ssam if (tp->t_line) 5826940Ssam (*linesw[tp->t_line].l_start)(tp); 5836940Ssam else 5846940Ssam dmfstart(tp); 5856940Ssam } 5866940Ssam } 5876940Ssam 5886940Ssam /* 5896940Ssam * Start (restart) transmission on the given DMF32 line. 5906940Ssam */ 5916940Ssam dmfstart(tp) 5926940Ssam register struct tty *tp; 5936940Ssam { 5946940Ssam register struct dmfdevice *addr; 5958607Sroot register int unit, nch; 5966940Ssam int s; 59721955Sbloom register int dmf; 5986940Ssam 5996940Ssam unit = minor(tp->t_dev); 60021955Sbloom dmf = unit >> 3; 6016940Ssam unit &= 07; 6026940Ssam addr = (struct dmfdevice *)tp->t_addr; 6036940Ssam 6046940Ssam /* 6056940Ssam * Must hold interrupts in following code to prevent 6066940Ssam * state of the tp from changing. 6076940Ssam */ 60821955Sbloom s = spltty(); 6096940Ssam /* 6106940Ssam * If it's currently active, or delaying, no need to do anything. 6116940Ssam */ 6126971Ssam if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 6136940Ssam goto out; 6146940Ssam /* 6156940Ssam * If there are still characters in the silo, 6166940Ssam * just reenable the transmitter. 6176940Ssam */ 6186940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6196940Ssam if (addr->dmftsc) { 6206940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 621*25449Skarels addr->dmflctms = addr->dmflctms | DMF_TE; 6226971Ssam tp->t_state |= TS_BUSY; 6236940Ssam goto out; 6246940Ssam } 6256940Ssam /* 6266940Ssam * If there are sleepers, and output has drained below low 6276940Ssam * water mark, wake up the sleepers. 6286940Ssam */ 62921955Sbloom if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 63021955Sbloom if (tp->t_state&TS_ASLEEP) { 63121955Sbloom tp->t_state &= ~TS_ASLEEP; 63221955Sbloom wakeup((caddr_t)&tp->t_outq); 63321955Sbloom } 63421955Sbloom if (tp->t_wsel) { 63521955Sbloom selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 63621955Sbloom tp->t_wsel = 0; 63721955Sbloom tp->t_state &= ~TS_WCOLL; 63821955Sbloom } 6396940Ssam } 6406940Ssam /* 6416940Ssam * Now restart transmission unless the output queue is 6426940Ssam * empty. 6436940Ssam */ 6446940Ssam if (tp->t_outq.c_cc == 0) 6456940Ssam goto out; 6469550Ssam if (tp->t_flags & (RAW|LITOUT)) 6476940Ssam nch = ndqb(&tp->t_outq, 0); 6486940Ssam else { 64921955Sbloom if ((nch = ndqb(&tp->t_outq, 0200)) == 0) { 65021955Sbloom /* 65121955Sbloom * If first thing on queue is a delay process it. 65221955Sbloom */ 6536940Ssam nch = getc(&tp->t_outq); 6546940Ssam timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 6556971Ssam tp->t_state |= TS_TIMEOUT; 6566940Ssam goto out; 6576940Ssam } 6586940Ssam } 6596940Ssam /* 6606940Ssam * If characters to transmit, restart transmission. 6616940Ssam */ 66221955Sbloom if (nch >= dmf_mindma) { 66321955Sbloom register car; 66421955Sbloom 66521955Sbloom dmf_dma[minor(tp->t_dev)] = 1; 6666940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 667*25449Skarels addr->dmflctms = addr->dmflctms | DMF_TE; 6686940Ssam car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); 6696940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; 6706940Ssam addr->dmftba = car; 67121955Sbloom addr->dmftcc = ((car >> 2) & 0xc000) | nch; 67221955Sbloom tp->t_state |= TS_BUSY; 67321955Sbloom } else if (nch) { 6746940Ssam register char *cp = tp->t_outq.c_cf; 6756940Ssam register int i; 6766940Ssam 67721955Sbloom dmf_dma[minor(tp->t_dev)] = 0; 6786940Ssam nch = MIN(nch, DMF_SILOCNT); 6796940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 680*25449Skarels addr->dmflctms = addr->dmflctms | DMF_TE; 6816940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6826940Ssam for (i = 0; i < nch; i++) 6836940Ssam addr->dmftbuf = *cp++; 6846940Ssam ndflush(&tp->t_outq, nch); 6856971Ssam tp->t_state |= TS_BUSY; 6866940Ssam } 6876940Ssam out: 6886940Ssam splx(s); 6896940Ssam } 6906940Ssam 6916940Ssam /* 6926940Ssam * Stop output on a line, e.g. for ^S/^Q or output flush. 6936940Ssam */ 6946940Ssam /*ARGSUSED*/ 6956940Ssam dmfstop(tp, flag) 6966940Ssam register struct tty *tp; 6976940Ssam { 6986940Ssam register struct dmfdevice *addr; 69921955Sbloom register unit = minor(tp->t_dev) & 7; 70021955Sbloom int s; 7016940Ssam 7026940Ssam addr = (struct dmfdevice *)tp->t_addr; 7036940Ssam /* 7046940Ssam * Block input/output interrupts while messing with state. 7056940Ssam */ 70621955Sbloom s = spltty(); 70721955Sbloom if (flag) { 70821955Sbloom addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 70921955Sbloom if (addr->dmftsc) { 71021955Sbloom /* 71121955Sbloom * Flush regardless of whether we're transmitting 71221955Sbloom * (TS_BUSY), if the silo contains untransmitted 71321955Sbloom * characters. 71421955Sbloom */ 71521955Sbloom addr->dmfcsr = DMFIR_LCR | unit | DMF_IE; 716*25449Skarels addr->dmflctms = addr->dmflctms | DMF_TE | DMF_FLUSH; 71721955Sbloom /* this will interrupt so let dmfxint handle the rest */ 71821955Sbloom tp->t_state |= TS_FLUSH|TS_BUSY; 71921955Sbloom } 72021955Sbloom } else { 72121955Sbloom if (tp->t_state & TS_BUSY) { 72221955Sbloom /* 72321955Sbloom * Stop transmission by disabling 72421955Sbloom * the transmitter. We'll pick up where we 72521955Sbloom * left off by reenabling in dmfstart. 72621955Sbloom */ 72721955Sbloom addr->dmfcsr = DMFIR_LCR | unit | DMF_IE; 728*25449Skarels addr->dmflctms = addr->dmflctms &~ DMF_TE; 72921955Sbloom /* no interrupt here */ 7306971Ssam tp->t_state &= ~TS_BUSY; 73121955Sbloom } 7326940Ssam } 7336940Ssam splx(s); 7346940Ssam } 7356940Ssam 7366940Ssam /* 7376940Ssam * DMF32 modem control 7386940Ssam */ 7396940Ssam dmfmctl(dev, bits, how) 7406940Ssam dev_t dev; 7416940Ssam int bits, how; 7426940Ssam { 7436940Ssam register struct dmfdevice *dmfaddr; 7446940Ssam register int unit, mbits, lcr; 7456940Ssam int s; 7466940Ssam 7476940Ssam unit = minor(dev); 7486940Ssam dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr); 7496940Ssam unit &= 07; 75021955Sbloom s = spltty(); 7516940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 7526940Ssam mbits = dmfaddr->dmfrms << 8; 7536940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 754*25449Skarels lcr = dmfaddr->dmflcmts; 755*25449Skarels mbits |= (lcr & 0xff00) >> 8; 7566940Ssam switch (how) { 7576940Ssam case DMSET: 75812449Ssam mbits = (mbits &0xff00) | bits; 7596940Ssam break; 7606940Ssam 7616940Ssam case DMBIS: 7626940Ssam mbits |= bits; 7636940Ssam break; 7646940Ssam 7656940Ssam case DMBIC: 7666940Ssam mbits &= ~bits; 7676940Ssam break; 7686940Ssam 7696940Ssam case DMGET: 7706940Ssam (void) splx(s); 7716940Ssam return(mbits); 7726940Ssam } 7736940Ssam if (mbits & DMF_BRK) 7746940Ssam lcr |= DMF_RBRK; 7756940Ssam else 7766940Ssam lcr &= ~DMF_RBRK; 777*25449Skarels dmfaddr->dmflctms = ((mbits & 037) << 8) | (lcr & 0xff); 7786940Ssam (void) splx(s); 7796940Ssam return(mbits); 7806940Ssam } 7816940Ssam 7826940Ssam /* 7836940Ssam * Reset state of driver if UBA reset was necessary. 7846940Ssam * Reset the csr, lpr, and lcr registers on open lines, and 7856940Ssam * restart transmitters. 7866940Ssam */ 7876940Ssam dmfreset(uban) 7886940Ssam int uban; 7896940Ssam { 7906940Ssam register int dmf, unit; 7916940Ssam register struct tty *tp; 7926940Ssam register struct uba_device *ui; 7936940Ssam register struct dmfdevice *addr; 7946940Ssam int i; 7956940Ssam 7966940Ssam for (dmf = 0; dmf < NDMF; dmf++) { 7976940Ssam ui = dmfinfo[dmf]; 7986940Ssam if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 7996940Ssam continue; 8006940Ssam printf(" dmf%d", dmf); 801*25449Skarels if (cbase[uban] == 0) { 802*25449Skarels dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 803*25449Skarels nclist*sizeof (struct cblock), 0); 804*25449Skarels cbase[uban] = dmf_ubinfo[uban]&0x3ffff; 805*25449Skarels } 8066940Ssam addr = (struct dmfdevice *)ui->ui_addr; 8076940Ssam addr->dmfcsr = DMF_IE; 80821955Sbloom addr->dmfrsp = dmf_timeout; 8096940Ssam unit = dmf * 8; 8106940Ssam for (i = 0; i < 8; i++) { 8116940Ssam tp = &dmf_tty[unit]; 8126971Ssam if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 8136940Ssam dmfparam(unit); 8148702Sroot (void) dmfmctl(unit, DMF_ON, DMSET); 8156971Ssam tp->t_state &= ~TS_BUSY; 8166940Ssam dmfstart(tp); 8176940Ssam } 8186940Ssam unit++; 8196940Ssam } 8206940Ssam } 8216940Ssam } 8226940Ssam 82321955Sbloom /* dmflopen -- open the line printer port on a dmf32 82421955Sbloom * 82521955Sbloom */ 82621955Sbloom dmflopen(dev,flag) 82721955Sbloom dev_t dev; 82821955Sbloom int flag; 82921955Sbloom { 83021955Sbloom register int dmf; 83121955Sbloom register struct dmfl_softc *sc; 83221955Sbloom register struct uba_device *ui; 83321955Sbloom register struct dmfdevice *addr; 83421955Sbloom 83521955Sbloom 83621955Sbloom dmf = DMFL_UNIT(dev) ; 83721955Sbloom if(((sc= &dmfl_softc[dmf])->dmfl_state & OPEN) || 83821955Sbloom ((ui=dmfinfo[dmf]) == 0) || ui->ui_alive == 0) 83921955Sbloom return(ENXIO); 84021955Sbloom addr = (struct dmfdevice *)ui->ui_addr; 84121955Sbloom if((addr->dmfl[0] & DMFL_OFFLINE)) 84221955Sbloom { 84321955Sbloom /*printf("dmf: line printer offline/jammed\n");*/ 84421955Sbloom return(EIO); 84521955Sbloom } 84621955Sbloom if((addr->dmfl[0]&DMFL_CONV)) 84721955Sbloom { 84821955Sbloom printf("dmf:line printer disconnected\n"); 84921955Sbloom return(EIO); 85021955Sbloom } 85121955Sbloom 85221955Sbloom addr->dmfl[0] = 0; 85321955Sbloom sc->dmfl_state |= OPEN; 85421955Sbloom return 0; 85521955Sbloom } 85621955Sbloom 85721955Sbloom dmflclose(dev,flag) 85821955Sbloom dev_t dev; 85921955Sbloom int flag; 86021955Sbloom { 86121955Sbloom register int dmf= DMFL_UNIT(dev); 86221955Sbloom register struct dmfl_softc *sc = &dmfl_softc[dmf]; 86321955Sbloom 86421955Sbloom dmflout(dev,"\f",1); 86521955Sbloom sc->dmfl_state = 0; 86621955Sbloom if(sc->dmfl_info != 0) 86721955Sbloom ubarelse((struct dmfdevice *)(dmfinfo[dmf])->ui_ubanum, 86821955Sbloom &(sc->dmfl_info)); 86921955Sbloom 87021955Sbloom ((struct dmfdevice *)(dmfinfo[dmf]->ui_addr))->dmfl[0]=0; 87121955Sbloom return 0; 87221955Sbloom } 87321955Sbloom 87421955Sbloom dmflwrite(dev,uio) 87521955Sbloom dev_t dev; 87621955Sbloom struct uio *uio; 87721955Sbloom { 87821955Sbloom register unsigned int n; 87921955Sbloom register int error; 88021955Sbloom register struct dmfl_softc *sc; 88121955Sbloom 88221955Sbloom sc = &dmfl_softc[DMFL_UNIT(dev)]; 88321955Sbloom if(sc->dmfl_state&ERROR) return(EIO); 88421955Sbloom while(n=min(DMFL_BUFSIZ,(unsigned)uio->uio_resid)) 88521955Sbloom { 88621955Sbloom if(error=uiomove(&sc->dmfl_buf[0],(int)n, 88721955Sbloom UIO_WRITE,uio)) 88821955Sbloom { 88921955Sbloom printf("uio move error\n"); 89021955Sbloom return(error); 89121955Sbloom } 89221955Sbloom if(error=dmflout(dev,&sc->dmfl_buf[0],n)) 89321955Sbloom { 89421955Sbloom return(error); 89521955Sbloom } 89621955Sbloom } 89721955Sbloom return 0; 89821955Sbloom } 89921955Sbloom 90021955Sbloom 90121955Sbloom /* dmflout -- start io operation to dmf line printer 90221955Sbloom * cp is addr of buf of n chars to be sent. 90321955Sbloom * 90421955Sbloom * -- dmf will be put in formatted output mode, this will 90521955Sbloom * be selectable from an ioctl if the 90621955Sbloom * need ever arises. 90721955Sbloom */ 90821955Sbloom dmflout(dev,cp,n) 90921955Sbloom dev_t dev; 91021955Sbloom char *cp; 91121955Sbloom int n; 91221955Sbloom { 91321955Sbloom register struct dmfl_softc *sc; 91421955Sbloom register int dmf; 91521955Sbloom register struct uba_device *ui; 91621955Sbloom register struct dmfdevice *d; 91721955Sbloom register unsigned info; 91821955Sbloom register unsigned i; 91921955Sbloom 92021955Sbloom dmf = DMFL_UNIT(dev) ; 92121955Sbloom sc= &dmfl_softc[dmf]; 92221955Sbloom if(sc->dmfl_state&ERROR) return(EIO); 92321955Sbloom ui= dmfinfo[dmf]; 92421955Sbloom /* allocate unibus resources, will be released when io 92521955Sbloom * operation is done 92621955Sbloom */ 92721955Sbloom sc->dmfl_info= 92821955Sbloom info= 92921955Sbloom uballoc(ui->ui_ubanum,cp,n,0); 93021955Sbloom d= (struct dmfdevice *)ui->ui_addr; 93121955Sbloom d->dmfl[0] = (2<<8) | DMFL_FORMAT; /* indir reg 2 */ 93221955Sbloom /* indir reg auto increments on r/w */ 93321955Sbloom /* SO DON'T CHANGE THE ORDER OF THIS CODE */ 93421955Sbloom d->dmfl[1] = 0; /* prefix chars & num */ 93521955Sbloom d->dmfl[1] = 0; /* suffix chars & num */ 93621955Sbloom d->dmfl[1] = info; /* dma lo 16 bits addr */ 93721955Sbloom 93821955Sbloom /* NOT DOCUMENTED !! */ 93921955Sbloom d->dmfl[1] = -n; /* number of chars */ 94021955Sbloom /* ----------^-------- */ 94121955Sbloom 94221955Sbloom d->dmfl[1] = ((info>>16)&3) /* dma hi 2 bits addr */ 94321955Sbloom | (1<<8) /* auto cr insert */ 94421955Sbloom | (1<<9) /* use real ff */ 94521955Sbloom | (1<<15); /* no u/l conversion */ 94621955Sbloom d->dmfl[1] = sc->dmfl_lines /* lines per page */ 94721955Sbloom | (sc->dmfl_cols<<8); /* carriage width */ 94821955Sbloom sc->dmfl_state |= ASLP; 94921955Sbloom i=spltty(); 95021955Sbloom d->dmfl[0] |= DMFL_PEN|DMFL_IE; 95121955Sbloom while(sc->dmfl_state & ASLP) 95221955Sbloom { 95321955Sbloom sleep(&sc->dmfl_buf[0],(PZERO+8)); 95421955Sbloom while(sc->dmfl_state&ERROR) 95521955Sbloom { 95621955Sbloom timeout(dmflint,dmf,10*hz); 95721955Sbloom sleep(&sc->dmfl_state,(PZERO+8)); 95821955Sbloom } 95921955Sbloom /*if(sc->dmfl_state&ERROR) return (EIO);*/ 96021955Sbloom } 96121955Sbloom splx(i); 96221955Sbloom return(0); 96321955Sbloom } 96421955Sbloom /* dmflint -- handle an interrupt from the line printer part of the dmf32 96521955Sbloom * 96621955Sbloom */ 96721955Sbloom 96821955Sbloom dmflint(dmf) 96921955Sbloom int dmf; 97021955Sbloom { 97121955Sbloom 97221955Sbloom register struct uba_device *ui; 97321955Sbloom register struct dmfl_softc *sc; 97421955Sbloom register struct dmfdevice *d; 97521955Sbloom 97621955Sbloom ui= dmfinfo[dmf]; 97721955Sbloom sc= &dmfl_softc[dmf]; 97821955Sbloom d= (struct dmfdevice *)ui->ui_addr; 97921955Sbloom 98021955Sbloom d->dmfl[0] &= ~DMFL_IE; 98121955Sbloom 98221955Sbloom if(sc->dmfl_state&ERROR) 98321955Sbloom { 98421955Sbloom printf("dmfl: intr while in error state \n"); 98521955Sbloom if((d->dmfl[0]&DMFL_OFFLINE) == 0) 98621955Sbloom sc->dmfl_state &= ~ERROR; 98721955Sbloom wakeup(&sc->dmfl_state); 98821955Sbloom return; 98921955Sbloom } 99021955Sbloom if(d->dmfl[0]&DMFL_DMAERR) 99121955Sbloom { 99221955Sbloom printf("dmf:NXM\n"); 99321955Sbloom } 99421955Sbloom if(d->dmfl[0]&DMFL_OFFLINE) 99521955Sbloom { 99621955Sbloom printf("dmf:printer error\n"); 99721955Sbloom sc->dmfl_state |= ERROR; 99821955Sbloom } 99921955Sbloom if(d->dmfl[0]&DMFL_PDONE) 100021955Sbloom { 100121955Sbloom #ifdef notdef 100221955Sbloom printf("bytes= %d\n",d->dmfl[1]); 100321955Sbloom printf("lines= %d\n",d->dmfl[1]); 100421955Sbloom #endif 100521955Sbloom } 100621955Sbloom sc->dmfl_state &= ~ASLP; 100721955Sbloom wakeup(&sc->dmfl_buf[0]); 100821955Sbloom if(sc->dmfl_info != 0) 100921955Sbloom ubarelse(ui->ui_ubanum,&sc->dmfl_info); 101021955Sbloom sc->dmfl_info = 0; 101121955Sbloom 101221955Sbloom } 101321955Sbloom 10146940Ssam /* stubs for interrupt routines for devices not yet supported */ 10156940Ssam 10166940Ssam dmfsrint() { printf("dmfsrint\n"); } 10176940Ssam 10186940Ssam dmfsxint() { printf("dmfsxint\n"); } 10196940Ssam 10206940Ssam dmfdaint() { printf("dmfdaint\n"); } 10216940Ssam 10226940Ssam dmfdbint() { printf("dmfdbint\n"); } 10236940Ssam 102421955Sbloom 10256940Ssam #endif 1026