/* * (C) 1984 UniSoft Corp. of Berkeley CA * * UniPlus Source Code. This program is proprietary * with Unisoft Corporation and is not to be reproduced * or used in any manner except as authorized in * writing by Unisoft. * * Driver for Centronix Citoh Dot Matrix Printer */ #include "sys/param.h" #include "sys/config.h" #include "sys/types.h" #include "sys/sysmacros.h" #include "sys/systm.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/file.h" #include "sys/tty.h" #include "sys/termio.h" #include "sys/conf.h" #include "sys/sysinfo.h" #include "sys/var.h" #include "sys/reg.h" #include "setjmp.h" #include "sys/mmu.h" #include "sys/cops.h" #include "sys/pport.h" extern struct device_d *pro_da[]; #define LPPRI (PZERO+8) #define LPLOWAT 40 #define LPHIWAT 100 #define LPMAX NPPDEVS struct lp { struct clist l_outq; char flag, ind; int ccc, mcc, mlc; int line, col; int dev; } lp_dt[LPMAX]; /* * flag values - PORT, CAP and NOCR bits from minor device */ #define PORT 0x0F /* which port - 1,2,4,5,7,8 */ #define CAP 0x10 #define NOCR 0x20 #define ASLP 0x40 /* only set within driver */ #define OPEN 0x80 /* only set within driver */ #define physical(d) ((minor(d)) & PORT) #define FORM 014 #define NO_OP asm(" nop ") char lpflg[LPMAX]; /* whether we expect another interrupt */ /* ARGSUSED */ lpopen(dev, mode) register dev_t dev; { register unit; register struct lp *lp; register unsigned char zero; register struct device_d *p; int lpintr(); extern char slot[]; unit = physical(dev); SPL5(); /* check expansion slot number and type (must be 2-port card) */ if (!PPOK(unit) || (slot[PPSLOT(unit)] != PR0)) { err: u.u_error = EIO; fini: SPL0(); return; } if ((lp = &lp_dt[unit])->flag) { goto err; } if (setppint(pro_da[unit],lpintr)) { /* port is already busy */ u.u_error = ENODEV; goto fini; } p = pro_da[unit]; zero = 0; p->d_acr = 0; /* no output latching */ NO_OP; p->d_pcr = 0x6B; /* set controller CA2 pulse mode strobe */ NO_OP; p->d_ddra = -1; /* set port A bits to output */ NO_OP; /*if (p == PPADDR) from system III p->d_ddrb &= 0x5C; set BSY and OCD to input else */ p->d_ddrb &= 0xDC; /* two or four port cards */ NO_OP; p->d_ddrb |= 0x9C; /* set port B bits 2,3,4,7 to out */ NO_OP; p->d_irb &= ~(DEN|DRW); /* disable buffers */ NO_OP; p->d_irb |= WCNT; /* set direction to output */ NO_OP; p->d_ier = FIRQ|FCA1; /* enable interrupt on busy */ NO_OP; zero = p->d_irb; if (zero & OCD) { /* out of paper ?? */ printf("lpopen: cable disconnect or out of paper\n"); out: freeppin(p); goto err; } if ((zero & PCHK) == 0) { /* online ?? */ printf("lpopen: (ddrb = %x) offline\n",zero); goto out; } lp->flag = (dev & (PORT | CAP | NOCR)) | OPEN; lp->ind = 4; lp->col = 80; lp->line = 66; lp->dev = dev; lpoutput(lp, FORM); SPL0(); } lpclose(dev) register dev_t dev; { register unit; register struct lp *lp; unit = physical(dev); lp = &lp_dt[unit]; lpoutput(lp, FORM); SPL5(); while (lpflg[unit]) { lp->flag |= ASLP; (void) sleep((caddr_t)lp, LPPRI); } freeppin(pro_da[unit]); lp->flag = 0; SPL0(); } lpwrite(dev) register dev_t dev; { register unit; register c; register struct lp *lp; unit = physical(dev); lp = &lp_dt[unit]; while (u.u_count) { SPL5(); while(lp->l_outq.c_cc > LPHIWAT) { lpintr(unit); lp->flag |= ASLP; (void) sleep((caddr_t)lp, LPPRI); } SPL0(); c = fubyte(u.u_base++); if (c < 0) { u.u_error = EFAULT; break; } u.u_count--; lpoutput(lp, c); } SPL5(); lpintr(unit); SPL0(); } lpoutput(lp, c) register struct lp *lp; register c; { if(lp->flag&CAP) { if(c>='a' && c<='z') c += 'A'-'a'; else switch(c) { case '{': c = '('; goto esc; case '}': c = ')'; goto esc; case '`': c = '\''; goto esc; case '|': c = '!'; goto esc; case '~': c = '^'; esc: lpoutput(lp, c); lp->ccc--; c = '-'; } } switch(c) { case '\t': lp->ccc = ((lp->ccc+8-lp->ind) & ~7) + lp->ind; return; case '\n': lp->mlc++; if(lp->mlc >= lp->line ) c = FORM; case FORM: lp->mcc = 0; if (lp->mlc) { (void) putc(c, &lp->l_outq); if(c == FORM) lp->mlc = 0; } case '\r': lp->ccc = lp->ind; SPL5(); lpintr(lp->dev); SPL0(); return; case 010: if(lp->ccc > lp->ind) lp->ccc--; return; case ' ': lp->ccc++; return; default: if(lp->ccc < lp->mcc) { if (lp->flag&NOCR) { lp->ccc++; return; } (void) putc('\r', &lp->l_outq); lp->mcc = 0; } if(lp->ccc < lp->col) { while(lp->ccc > lp->mcc) { (void) putc(' ', &lp->l_outq); lp->mcc++; } (void) putc(c, &lp->l_outq); lp->mcc++; } lp->ccc++; } } lpintr(dev) register dev; { register struct lp *lp; register struct device_d *p; register c; dev = physical(dev); if (lpflg[dev]) return; lp = &lp_dt[dev]; p = pro_da[dev]; while ((c = getc(&lp->l_outq)) >= 0) { lpflg[dev] = 1; p->d_ira = c; c = 30; while ((p->d_ifr & FCA1) == 0) { if (--c <= 0) return; } lpflg[dev] = 0; } if (lp->l_outq.c_cc <= LPLOWAT && lp->flag&ASLP) { lp->flag &= ~ASLP; wakeup((caddr_t)lp); } } /* ARGSUSED */ lpioctl(dev, cmd, arg, mode) { }