| 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,230 – 2001/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, }; | |