1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 /* Centronix parallel (printer) port */ 10 11 /* base addresses */ 12 static int lptbase[] = { 13 0x3bc, /* lpt1 */ 14 0x378, /* lpt2 (sic) */ 15 0x278 /* lpt3 (sic) */ 16 }; 17 #define NDEV (sizeof lptbase/sizeof lptbase[0]) 18 19 /* offsets, and bits in the registers */ 20 enum 21 { 22 /* data latch register */ 23 Qdlr= 0x0, 24 /* printer status register */ 25 Qpsr= 0x1, 26 Fnotbusy= 0x80, 27 Fack= 0x40, 28 Fpe= 0x20, 29 Fselect= 0x10, 30 Fnoerror= 0x08, 31 /* printer control register */ 32 Qpcr= 0x2, 33 Fie= 0x10, 34 Fselectin= 0x08, 35 Finitbar= 0x04, 36 Faf= 0x02, 37 Fstrobe= 0x01, 38 /* fake `data register' */ 39 Qdata= 0x3, 40 }; 41 42 static int lptready(void*); 43 static void outch(int, int); 44 static void lptintr(Ureg*, void*); 45 46 static Rendez lptrendez; 47 48 Dirtab lptdir[]={ 49 "dlr", {Qdlr}, 1, 0666, 50 "psr", {Qpsr}, 5, 0444, 51 "pcr", {Qpcr}, 0, 0222, 52 "data", {Qdata}, 0, 0222, 53 }; 54 #define NLPT (sizeof lptdir/sizeof lptdir[0]) 55 56 static int 57 lptgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 58 { 59 Qid qid; 60 char name[NAMELEN]; 61 62 if(tab==0 || i>=ntab) 63 return -1; 64 tab += i; 65 qid = tab->qid; 66 if(qid.path < Qdata) 67 qid.path += lptbase[c->dev]; 68 qid.vers = c->dev; 69 sprint(name, "lpt%d%s", c->dev+1, tab->name); 70 devdir(c, qid, name, tab->length, eve, tab->perm, dp); 71 return 1; 72 } 73 74 void 75 lptreset(void) 76 { 77 } 78 79 void 80 lptinit(void) 81 {} 82 83 Chan* 84 lptattach(char *spec) 85 { 86 Chan *c; 87 int i = (spec && *spec) ? strtol(spec, 0, 0) : 1; 88 static int set; 89 90 if(!set){ 91 set = 1; 92 setvec(Parallelvec, lptintr, 0); 93 } 94 if(i < 1 || i > NDEV) 95 error(Ebadarg); 96 c = devattach('L', spec); 97 c->dev = i-1; 98 return c; 99 } 100 101 Chan* 102 lptclone(Chan *c, Chan *nc) 103 { 104 return devclone(c, nc); 105 } 106 107 int 108 lptwalk(Chan *c, char *name) 109 { 110 return devwalk(c, name, lptdir, NLPT, lptgen); 111 } 112 113 void 114 lptstat(Chan *c, char *dp) 115 { 116 devstat(c, dp, lptdir, NLPT, lptgen); 117 } 118 119 Chan* 120 lptopen(Chan *c, int omode) 121 { 122 return devopen(c, omode, lptdir, NLPT, lptgen); 123 } 124 125 void 126 lptcreate(Chan *c, char *name, int omode, ulong perm) 127 { 128 USED(c, name, omode, perm); 129 error(Eperm); 130 } 131 132 void 133 lptclose(Chan *c) 134 { 135 USED(c); 136 } 137 138 void 139 lptremove(Chan *c) 140 { 141 USED(c); 142 error(Eperm); 143 } 144 145 void 146 lptwstat(Chan *c, char *dp) 147 { 148 USED(c, dp); 149 error(Eperm); 150 } 151 152 long 153 lptread(Chan *c, void *a, long n) 154 { 155 char str[16]; int size; 156 157 if(c->qid.path == CHDIR) 158 return devdirread(c, a, n, lptdir, NLPT, lptgen); 159 size = sprint(str, "0x%2.2ux\n", inb(c->qid.path)); 160 if(c->offset >= size) 161 return 0; 162 if(c->offset+n > size) 163 n = size-c->offset; 164 memmove(a, str+c->offset, n); 165 return n; 166 } 167 168 long 169 lptwrite(Chan *c, void *a, long n) 170 { 171 char str[16], *p; 172 long base, k; 173 174 if(n <= 0) 175 return 0; 176 if(c->qid.path != Qdata){ 177 if(n > sizeof str-1) 178 n = sizeof str-1; 179 memmove(str, a, n); 180 str[n] = 0; 181 outb(c->qid.path, strtoul(str, 0, 0)); 182 return n; 183 } 184 p = a; 185 k = n; 186 base = lptbase[c->dev]; 187 if(waserror()){ 188 outb(base+Qpcr, Finitbar); 189 nexterror(); 190 } 191 while(--k >= 0) 192 outch(base, *p++); 193 poperror(); 194 return n; 195 } 196 197 static void 198 outch(int base, int c) 199 { 200 int status, tries; 201 202 for(tries = 0;; tries++){ 203 status = inb(base+Qpsr); 204 if(!(status & Fselect) || !(status & Fnoerror)) 205 error(Eio); 206 if(status & Fnotbusy) 207 break; 208 if(tries > 1000){ 209 outb(base+Qpcr, Finitbar|Fie); 210 tsleep(&lptrendez, lptready, (void *)base, MS2HZ); 211 } 212 } 213 outb(base+Qdlr, c); 214 outb(base+Qpcr, Finitbar|Fstrobe); 215 outb(base+Qpcr, Finitbar); 216 } 217 218 static int 219 lptready(void *base) 220 { 221 return inb((int)base+Qpsr)&Fnotbusy; 222 } 223 224 static void 225 lptintr(Ureg *ur, void *a) 226 { 227 USED(ur, a); 228 wakeup(&lptrendez); 229 } 230