xref: /plan9-contrib/sys/src/9/pc/devlpt.c (revision 57d98441a62fcee6012d93fcd1f7724ec4b1afe9)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"io.h"
73e12c5d1SDavid du Colombier #include	"../port/error.h"
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier /* Centronix parallel (printer) port */
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier /* base addresses */
123e12c5d1SDavid du Colombier static int lptbase[] = {
137dd7cddfSDavid du Colombier 	0x378,	/* lpt1 */
147dd7cddfSDavid du Colombier 	0x3bc,	/* lpt2 */
153e12c5d1SDavid du Colombier 	0x278	/* lpt3 (sic) */
163e12c5d1SDavid du Colombier };
177dd7cddfSDavid du Colombier #define NDEV	nelem(lptbase)
187dd7cddfSDavid du Colombier static int lptallocd[NDEV];
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier /* offsets, and bits in the registers */
213e12c5d1SDavid du Colombier enum
223e12c5d1SDavid du Colombier {
239a747e4fSDavid du Colombier 	Qdir=		0x8000,
243e12c5d1SDavid du Colombier 	/* data latch register */
253e12c5d1SDavid du Colombier 	Qdlr=		0x0,
263e12c5d1SDavid du Colombier 	/* printer status register */
273e12c5d1SDavid du Colombier 	Qpsr=		0x1,
283e12c5d1SDavid du Colombier 	Fnotbusy=	0x80,
293e12c5d1SDavid du Colombier 	Fack=		0x40,
303e12c5d1SDavid du Colombier 	Fpe=		0x20,
313e12c5d1SDavid du Colombier 	Fselect=	0x10,
323e12c5d1SDavid du Colombier 	Fnoerror=	0x08,
333e12c5d1SDavid du Colombier 	/* printer control register */
343e12c5d1SDavid du Colombier 	Qpcr=		0x2,
353e12c5d1SDavid du Colombier 	Fie=		0x10,
363e12c5d1SDavid du Colombier 	Fselectin=	0x08,
373e12c5d1SDavid du Colombier 	Finitbar=	0x04,
383e12c5d1SDavid du Colombier 	Faf=		0x02,
393e12c5d1SDavid du Colombier 	Fstrobe=	0x01,
403e12c5d1SDavid du Colombier 	/* fake `data register' */
413e12c5d1SDavid du Colombier 	Qdata=		0x3,
423e12c5d1SDavid du Colombier };
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier static int	lptready(void*);
453e12c5d1SDavid du Colombier static void	outch(int, int);
46219b2ee8SDavid du Colombier static void	lptintr(Ureg*, void*);
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier static Rendez	lptrendez;
493e12c5d1SDavid du Colombier 
503e12c5d1SDavid du Colombier Dirtab lptdir[]={
519a747e4fSDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,	DMDIR|0555,
523e12c5d1SDavid du Colombier 	"dlr",	{Qdlr},			1,	0666,
533e12c5d1SDavid du Colombier 	"psr",	{Qpsr},			5,	0444,
543e12c5d1SDavid du Colombier 	"pcr",	{Qpcr},			0,	0222,
553e12c5d1SDavid du Colombier 	"data",	{Qdata},		0,	0222,
563e12c5d1SDavid du Colombier };
573e12c5d1SDavid du Colombier 
583e12c5d1SDavid du Colombier static int
lptgen(Chan * c,char *,Dirtab * tab,int ntab,int i,Dir * dp)599a747e4fSDavid du Colombier lptgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
603e12c5d1SDavid du Colombier {
613e12c5d1SDavid du Colombier 	Qid qid;
623e12c5d1SDavid du Colombier 
637dd7cddfSDavid du Colombier 	if(i == DEVDOTDOT){
649a747e4fSDavid du Colombier 		mkqid(&qid, Qdir, 0, QTDIR);
659a747e4fSDavid du Colombier 		devdir(c, qid, ".", 0, eve, 0555, dp);
667dd7cddfSDavid du Colombier 		return 1;
677dd7cddfSDavid du Colombier 	}
689a747e4fSDavid du Colombier 	i++; /* skip first element for . itself */
693e12c5d1SDavid du Colombier 	if(tab==0 || i>=ntab)
703e12c5d1SDavid du Colombier 		return -1;
713e12c5d1SDavid du Colombier 	tab += i;
723e12c5d1SDavid du Colombier 	qid = tab->qid;
739a747e4fSDavid du Colombier 	qid.path &= ~Qdir;
743e12c5d1SDavid du Colombier 	if(qid.path < Qdata)
753e12c5d1SDavid du Colombier 		qid.path += lptbase[c->dev];
763e12c5d1SDavid du Colombier 	qid.vers = c->dev;
77*57d98441SDavid du Colombier 	snprint(up->genbuf, sizeof up->genbuf, "lpt%lud%s", c->dev+1, tab->name);
789a747e4fSDavid du Colombier 	devdir(c, qid, up->genbuf, tab->length, eve, tab->perm, dp);
793e12c5d1SDavid du Colombier 	return 1;
803e12c5d1SDavid du Colombier }
813e12c5d1SDavid du Colombier 
827dd7cddfSDavid du Colombier static Chan*
lptattach(char * spec)833e12c5d1SDavid du Colombier lptattach(char *spec)
843e12c5d1SDavid du Colombier {
853e12c5d1SDavid du Colombier 	Chan *c;
863e12c5d1SDavid du Colombier 	int i  = (spec && *spec) ? strtol(spec, 0, 0) : 1;
87*57d98441SDavid du Colombier 	char name[8];
88219b2ee8SDavid du Colombier 	static int set;
893e12c5d1SDavid du Colombier 
90219b2ee8SDavid du Colombier 	if(!set){
917dd7cddfSDavid du Colombier 		outb(lptbase[i-1]+Qpcr, 0);	/* turn off interrupts */
92219b2ee8SDavid du Colombier 		set = 1;
937dd7cddfSDavid du Colombier 		intrenable(IrqLPT, lptintr, 0, BUSUNKNOWN, "lpt");
94219b2ee8SDavid du Colombier 	}
953e12c5d1SDavid du Colombier 	if(i < 1 || i > NDEV)
963e12c5d1SDavid du Colombier 		error(Ebadarg);
977dd7cddfSDavid du Colombier 	if(lptallocd[i-1] == 0){
989a747e4fSDavid du Colombier 		int ecr;
99*57d98441SDavid du Colombier 		snprint(name, sizeof name, "lpt%d", i-1);
1007dd7cddfSDavid du Colombier 		if(ioalloc(lptbase[i-1], 3, 0, name) < 0)
1017dd7cddfSDavid du Colombier 			error("lpt port space in use");
1027dd7cddfSDavid du Colombier 		lptallocd[i-1] = 1;
10341dd6b47SDavid du Colombier 		/* Detect ECP - if found, put into PS/2 mode to suit style of driver */
1049a747e4fSDavid du Colombier 		ecr = lptbase[i-1] + 0x402;
1059a747e4fSDavid du Colombier 		if ((inb(ecr) & 3) == 1) {
1069a747e4fSDavid du Colombier 			outb(ecr, 0x34);
1079a747e4fSDavid du Colombier 			if (inb(ecr) == 0x35) {
1089a747e4fSDavid du Colombier 				outb(ecr, (inb(ecr) & 0x1f) | (1 << 5));
1099a747e4fSDavid du Colombier 				if(ioalloc(ecr, 1, 0, name) < 0)
1109a747e4fSDavid du Colombier 					error("lpt ecr port space in use");
1119a747e4fSDavid du Colombier 			}
1129a747e4fSDavid du Colombier 		}
1137dd7cddfSDavid du Colombier 	}
1143e12c5d1SDavid du Colombier 	c = devattach('L', spec);
1159a747e4fSDavid du Colombier 	c->qid.path = Qdir;
1163e12c5d1SDavid du Colombier 	c->dev = i-1;
1173e12c5d1SDavid du Colombier 	return c;
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier 
1209a747e4fSDavid du Colombier static Walkqid*
lptwalk(Chan * c,Chan * nc,char ** name,int nname)1219a747e4fSDavid du Colombier lptwalk(Chan *c, Chan *nc, char **name, int nname)
1223e12c5d1SDavid du Colombier {
1239a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, lptdir, nelem(lptdir), lptgen);
1243e12c5d1SDavid du Colombier }
1253e12c5d1SDavid du Colombier 
1269a747e4fSDavid du Colombier static int
lptstat(Chan * c,uchar * dp,int n)1279a747e4fSDavid du Colombier lptstat(Chan *c, uchar *dp, int n)
1283e12c5d1SDavid du Colombier {
1299a747e4fSDavid du Colombier 	return devstat(c, dp, n, lptdir, nelem(lptdir), lptgen);
1303e12c5d1SDavid du Colombier }
1313e12c5d1SDavid du Colombier 
1327dd7cddfSDavid du Colombier static Chan*
lptopen(Chan * c,int omode)1333e12c5d1SDavid du Colombier lptopen(Chan *c, int omode)
1343e12c5d1SDavid du Colombier {
1357dd7cddfSDavid du Colombier 	return devopen(c, omode, lptdir, nelem(lptdir), lptgen);
1363e12c5d1SDavid du Colombier }
1373e12c5d1SDavid du Colombier 
1387dd7cddfSDavid du Colombier static void
lptclose(Chan *)1397dd7cddfSDavid du Colombier lptclose(Chan *)
1403e12c5d1SDavid du Colombier {
1413e12c5d1SDavid du Colombier }
1423e12c5d1SDavid du Colombier 
1437dd7cddfSDavid du Colombier static long
lptread(Chan * c,void * a,long n,vlong)1447dd7cddfSDavid du Colombier lptread(Chan *c, void *a, long n, vlong)
1453e12c5d1SDavid du Colombier {
1467dd7cddfSDavid du Colombier 	char str[16];
1477dd7cddfSDavid du Colombier 	int size;
1487dd7cddfSDavid du Colombier 	ulong o;
1493e12c5d1SDavid du Colombier 
1509a747e4fSDavid du Colombier 	if(c->qid.path == Qdir)
1517dd7cddfSDavid du Colombier 		return devdirread(c, a, n, lptdir, nelem(lptdir), lptgen);
152*57d98441SDavid du Colombier 	size = snprint(str, sizeof str, "0x%2.2ux\n", inb(c->qid.path));
1537dd7cddfSDavid du Colombier 	o = c->offset;
1547dd7cddfSDavid du Colombier 	if(o >= size)
1553e12c5d1SDavid du Colombier 		return 0;
1567dd7cddfSDavid du Colombier 	if(o+n > size)
1573e12c5d1SDavid du Colombier 		n = size-c->offset;
1587dd7cddfSDavid du Colombier 	memmove(a, str+o, n);
1593e12c5d1SDavid du Colombier 	return n;
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier 
1627dd7cddfSDavid du Colombier static long
lptwrite(Chan * c,void * a,long n,vlong)1637dd7cddfSDavid du Colombier lptwrite(Chan *c, void *a, long n, vlong)
1643e12c5d1SDavid du Colombier {
1653e12c5d1SDavid du Colombier 	char str[16], *p;
1663e12c5d1SDavid du Colombier 	long base, k;
1673e12c5d1SDavid du Colombier 
1683e12c5d1SDavid du Colombier 	if(n <= 0)
1693e12c5d1SDavid du Colombier 		return 0;
1703e12c5d1SDavid du Colombier 	if(c->qid.path != Qdata){
1713e12c5d1SDavid du Colombier 		if(n > sizeof str-1)
1723e12c5d1SDavid du Colombier 			n = sizeof str-1;
1733e12c5d1SDavid du Colombier 		memmove(str, a, n);
1743e12c5d1SDavid du Colombier 		str[n] = 0;
1753e12c5d1SDavid du Colombier 		outb(c->qid.path, strtoul(str, 0, 0));
1763e12c5d1SDavid du Colombier 		return n;
1773e12c5d1SDavid du Colombier 	}
1783e12c5d1SDavid du Colombier 	p = a;
1793e12c5d1SDavid du Colombier 	k = n;
1803e12c5d1SDavid du Colombier 	base = lptbase[c->dev];
1813e12c5d1SDavid du Colombier 	if(waserror()){
1823e12c5d1SDavid du Colombier 		outb(base+Qpcr, Finitbar);
1833e12c5d1SDavid du Colombier 		nexterror();
1843e12c5d1SDavid du Colombier 	}
1853e12c5d1SDavid du Colombier 	while(--k >= 0)
1863e12c5d1SDavid du Colombier 		outch(base, *p++);
1873e12c5d1SDavid du Colombier 	poperror();
1883e12c5d1SDavid du Colombier 	return n;
1893e12c5d1SDavid du Colombier }
1903e12c5d1SDavid du Colombier 
1913e12c5d1SDavid du Colombier static void
outch(int base,int c)1923e12c5d1SDavid du Colombier outch(int base, int c)
1933e12c5d1SDavid du Colombier {
194219b2ee8SDavid du Colombier 	int status, tries;
1953e12c5d1SDavid du Colombier 
196219b2ee8SDavid du Colombier 	for(tries=0;; tries++) {
197219b2ee8SDavid du Colombier 		status = inb(base+Qpsr);
198219b2ee8SDavid du Colombier 		if(status&Fnotbusy)
199219b2ee8SDavid du Colombier 			break;
20059cc4ca5SDavid du Colombier 		if((status&Fpe)==0 && (status&(Fselect|Fnoerror)) != (Fselect|Fnoerror))
20159cc4ca5SDavid du Colombier 			error(Eio);
2023e12c5d1SDavid du Colombier 		outb(base+Qpcr, Finitbar|Fie);
20359cc4ca5SDavid du Colombier 		tsleep(&lptrendez, lptready, (void *)base, 100);
204219b2ee8SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier 	outb(base+Qdlr, c);
2063e12c5d1SDavid du Colombier 	outb(base+Qpcr, Finitbar|Fstrobe);
2073e12c5d1SDavid du Colombier 	outb(base+Qpcr, Finitbar);
2083e12c5d1SDavid du Colombier }
2093e12c5d1SDavid du Colombier 
2103e12c5d1SDavid du Colombier static int
lptready(void * base)2113e12c5d1SDavid du Colombier lptready(void *base)
2123e12c5d1SDavid du Colombier {
2133e12c5d1SDavid du Colombier 	return inb((int)base+Qpsr)&Fnotbusy;
2143e12c5d1SDavid du Colombier }
2153e12c5d1SDavid du Colombier 
2163e12c5d1SDavid du Colombier static void
lptintr(Ureg *,void *)2177dd7cddfSDavid du Colombier lptintr(Ureg *, void *)
2183e12c5d1SDavid du Colombier {
2193e12c5d1SDavid du Colombier 	wakeup(&lptrendez);
2203e12c5d1SDavid du Colombier }
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier Dev lptdevtab = {
2237dd7cddfSDavid du Colombier 	'L',
2247dd7cddfSDavid du Colombier 	"lpt",
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	devreset,
2277dd7cddfSDavid du Colombier 	devinit,
2289a747e4fSDavid du Colombier 	devshutdown,
2297dd7cddfSDavid du Colombier 	lptattach,
2307dd7cddfSDavid du Colombier 	lptwalk,
2317dd7cddfSDavid du Colombier 	lptstat,
2327dd7cddfSDavid du Colombier 	lptopen,
2337dd7cddfSDavid du Colombier 	devcreate,
2347dd7cddfSDavid du Colombier 	lptclose,
2357dd7cddfSDavid du Colombier 	lptread,
2367dd7cddfSDavid du Colombier 	devbread,
2377dd7cddfSDavid du Colombier 	lptwrite,
2387dd7cddfSDavid du Colombier 	devbwrite,
2397dd7cddfSDavid du Colombier 	devremove,
2407dd7cddfSDavid du Colombier 	devwstat,
2417dd7cddfSDavid du Colombier };
242