plan 9 kernel history: overview | file list | diff list

2000/0813/pc/devlpt.c (diff list | history)

2000/0813/sys/src/9/pc/devlpt.c:1,2302001/0413/sys/src/9/pc/devlpt.c:1,241 (short | long | prev | next)
Handle ECP parallel ports.
rsc Fri Mar 4 12:44:25 2005
1991/1204    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/1204    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
1992/0111    
#include	"../port/error.h" 
1991/1204    
 
/* Centronix parallel (printer) port */ 
 
/* base addresses */ 
1992/0205    
static int lptbase[] = { 
1994/0324    
	0x378,	/* lpt1 */ 
	0x3bc,	/* lpt2 */ 
1991/1204    
	0x278	/* lpt3 (sic) */ 
}; 
1999/0714    
#define NDEV	nelem(lptbase) 
static int lptallocd[NDEV]; 
1991/1204    
 
/* offsets, and bits in the registers */ 
enum 
{ 
	/* data latch register */ 
	Qdlr=		0x0, 
	/* printer status register */ 
	Qpsr=		0x1, 
	Fnotbusy=	0x80, 
	Fack=		0x40, 
	Fpe=		0x20, 
	Fselect=	0x10, 
	Fnoerror=	0x08, 
	/* printer control register */ 
	Qpcr=		0x2, 
	Fie=		0x10, 
	Fselectin=	0x08, 
	Finitbar=	0x04, 
	Faf=		0x02, 
	Fstrobe=	0x01, 
	/* fake `data register' */ 
	Qdata=		0x3, 
}; 
 
static int	lptready(void*); 
static void	outch(int, int); 
1994/0324    
static void	lptintr(Ureg*, void*); 
1991/1204    
 
static Rendez	lptrendez; 
 
Dirtab lptdir[]={ 
	"dlr",		{Qdlr},		1,		0666, 
	"psr",		{Qpsr},		5,		0444, 
	"pcr",		{Qpcr},		0,		0222, 
	"data",		{Qdata},	0,		0222, 
}; 
 
static int 
lptgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 
{ 
	Qid qid; 
	char name[NAMELEN]; 
 
1999/1230    
	if(i == DEVDOTDOT){ 
		sprint(name, "#L%lud", c->dev+1); 
		devdir(c, (Qid){CHDIR, 0}, name, 0, eve, 0555, dp); 
		return 1; 
	} 
1991/1204    
	if(tab==0 || i>=ntab) 
		return -1; 
	tab += i; 
	qid = tab->qid; 
	if(qid.path < Qdata) 
		qid.path += lptbase[c->dev]; 
	qid.vers = c->dev; 
1998/0825    
	sprint(name, "lpt%lud%s", c->dev+1, tab->name); 
1991/1204    
	devdir(c, qid, name, tab->length, eve, tab->perm, dp); 
	return 1; 
} 
 
1997/0327    
static Chan* 
1991/1204    
lptattach(char *spec) 
{ 
	Chan *c; 
	int i  = (spec && *spec) ? strtol(spec, 0, 0) : 1; 
1999/0714    
	char name[5]; 
1993/0224    
	static int set; 
1991/1204    
 
1993/0224    
	if(!set){ 
1994/0513    
		outb(lptbase[i-1]+Qpcr, 0);	/* turn off interrupts */ 
1993/0224    
		set = 1; 
1999/0819    
		intrenable(IrqLPT, lptintr, 0, BUSUNKNOWN, "lpt"); 
1993/0224    
	} 
1991/1204    
	if(i < 1 || i > NDEV) 
1992/0114    
		error(Ebadarg); 
1999/0714    
	if(lptallocd[i-1] == 0){ 
2001/0413    
		int ecr; 
1999/0714    
		sprint(name, "lpt%d", i-1); 
		if(ioalloc(lptbase[i-1], 3, 0, name) < 0) 
			error("lpt port space in use"); 
		lptallocd[i-1] = 1; 
2001/0413    
		// Detect ECP - if found, put into PS/2 mode to suit style of driver 
		ecr = lptbase[i-1] + 0x402; 
		if ((inb(ecr) & 3) == 1) { 
			outb(ecr, 0x34); 
			if (inb(ecr) == 0x35) { 
				outb(ecr, (inb(ecr) & 0x1f) | (1 << 5)); 
				if(ioalloc(ecr, 1, 0, name) < 0) 
					error("lpt ecr port space in use"); 
			} 
		} 
1999/0714    
	} 
1991/1204    
	c = devattach('L', spec); 
	c->dev = i-1; 
	return c; 
} 
 
1997/0327    
static int 
1991/1204    
lptwalk(Chan *c, char *name) 
{ 
1997/0327    
	return devwalk(c, name, lptdir, nelem(lptdir), lptgen); 
1991/1204    
} 
 
1997/0327    
static void 
1991/1204    
lptstat(Chan *c, char *dp) 
{ 
1997/0327    
	devstat(c, dp, lptdir, nelem(lptdir), lptgen); 
1991/1204    
} 
 
1997/0327    
static Chan* 
1991/1204    
lptopen(Chan *c, int omode) 
{ 
1997/0327    
	return devopen(c, omode, lptdir, nelem(lptdir), lptgen); 
1991/1204    
} 
 
1997/0327    
static void 
1998/0319    
lptclose(Chan *) 
1992/0711    
{ 
} 
1991/1204    
 
1997/0327    
static long 
1998/0319    
lptread(Chan *c, void *a, long n, vlong) 
1991/1204    
{ 
1998/0319    
	char str[16]; 
	int size; 
	ulong o; 
1991/1204    
 
	if(c->qid.path == CHDIR) 
1997/0327    
		return devdirread(c, a, n, lptdir, nelem(lptdir), lptgen); 
1991/1204    
	size = sprint(str, "0x%2.2ux\n", inb(c->qid.path)); 
1998/0319    
	o = c->offset; 
	if(o >= size) 
1991/1204    
		return 0; 
1998/0319    
	if(o+n > size) 
1991/1204    
		n = size-c->offset; 
1998/0319    
	memmove(a, str+o, n); 
1991/1204    
	return n; 
} 
 
1997/0327    
static long 
1998/0319    
lptwrite(Chan *c, void *a, long n, vlong) 
1995/0108    
{ 
1991/1204    
	char str[16], *p; 
	long base, k; 
 
	if(n <= 0) 
		return 0; 
	if(c->qid.path != Qdata){ 
		if(n > sizeof str-1) 
			n = sizeof str-1; 
		memmove(str, a, n); 
		str[n] = 0; 
		outb(c->qid.path, strtoul(str, 0, 0)); 
		return n; 
	} 
	p = a; 
	k = n; 
	base = lptbase[c->dev]; 
	if(waserror()){ 
		outb(base+Qpcr, Finitbar); 
		nexterror(); 
	} 
	while(--k >= 0) 
		outch(base, *p++); 
	poperror(); 
	return n; 
1995/0108    
} 
 
1991/1204    
static void 
outch(int base, int c) 
{ 
1994/0331    
	int status, tries; 
1991/1204    
 
2000/0813    
	for(tries=0;; tries++) { 
1994/0331    
		status = inb(base+Qpsr); 
2000/0813    
		if(status&Fnotbusy) 
1994/0331    
			break; 
2000/0813    
		if((status&Fpe)==0 && (status&(Fselect|Fnoerror)) != (Fselect|Fnoerror)) 
			error(Eio); 
		if(tries < 10) 
			tsleep(&lptrendez, return0, nil, 1); 
		else { 
1994/0331    
			outb(base+Qpcr, Finitbar|Fie); 
2000/0813    
			tsleep(&lptrendez, lptready, (void *)base, 100); 
1994/0331    
		} 
1991/1204    
	} 
	outb(base+Qdlr, c); 
	outb(base+Qpcr, Finitbar|Fstrobe); 
	outb(base+Qpcr, Finitbar); 
} 
 
static int 
lptready(void *base) 
{ 
	return inb((int)base+Qpsr)&Fnotbusy; 
} 
 
static void 
1998/0319    
lptintr(Ureg *, void *) 
1991/1204    
{ 
	wakeup(&lptrendez); 
} 
1997/0327    
 
Dev lptdevtab = { 
1997/0408    
	'L', 
	"lpt", 
 
1997/0327    
	devreset, 
	devinit, 
	lptattach, 
	devclone, 
	lptwalk, 
	lptstat, 
	lptopen, 
	devcreate, 
	lptclose, 
	lptread, 
	devbread, 
	lptwrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)