FreeBSD/Linux Kernel Cross Reference
sys/pc/devlpt.c
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 0x378, /* lpt1 */
14 0x3bc, /* lpt2 */
15 0x278 /* lpt3 (sic) */
16 };
17 #define NDEV nelem(lptbase)
18 static int lptallocd[NDEV];
19
20 /* offsets, and bits in the registers */
21 enum
22 {
23 Qdir= 0x8000,
24 /* data latch register */
25 Qdlr= 0x0,
26 /* printer status register */
27 Qpsr= 0x1,
28 Fnotbusy= 0x80,
29 Fack= 0x40,
30 Fpe= 0x20,
31 Fselect= 0x10,
32 Fnoerror= 0x08,
33 /* printer control register */
34 Qpcr= 0x2,
35 Fie= 0x10,
36 Fselectin= 0x08,
37 Finitbar= 0x04,
38 Faf= 0x02,
39 Fstrobe= 0x01,
40 /* fake `data register' */
41 Qdata= 0x3,
42 };
43
44 static int lptready(void*);
45 static void outch(int, int);
46 static void lptintr(Ureg*, void*);
47
48 static Rendez lptrendez;
49
50 Dirtab lptdir[]={
51 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
52 "dlr", {Qdlr}, 1, 0666,
53 "psr", {Qpsr}, 5, 0444,
54 "pcr", {Qpcr}, 0, 0222,
55 "data", {Qdata}, 0, 0222,
56 };
57
58 static int
59 lptgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
60 {
61 Qid qid;
62
63 if(i == DEVDOTDOT){
64 mkqid(&qid, Qdir, 0, QTDIR);
65 devdir(c, qid, ".", 0, eve, 0555, dp);
66 return 1;
67 }
68 i++; /* skip first element for . itself */
69 if(tab==0 || i>=ntab)
70 return -1;
71 tab += i;
72 qid = tab->qid;
73 qid.path &= ~Qdir;
74 if(qid.path < Qdata)
75 qid.path += lptbase[c->dev];
76 qid.vers = c->dev;
77 sprint(up->genbuf, "lpt%lud%s", c->dev+1, tab->name);
78 devdir(c, qid, up->genbuf, tab->length, eve, tab->perm, dp);
79 return 1;
80 }
81
82 static Chan*
83 lptattach(char *spec)
84 {
85 Chan *c;
86 int i = (spec && *spec) ? strtol(spec, 0, 0) : 1;
87 char name[5];
88 static int set;
89
90 if(!set){
91 outb(lptbase[i-1]+Qpcr, 0); /* turn off interrupts */
92 set = 1;
93 intrenable(IrqLPT, lptintr, 0, BUSUNKNOWN, "lpt");
94 }
95 if(i < 1 || i > NDEV)
96 error(Ebadarg);
97 if(lptallocd[i-1] == 0){
98 int ecr;
99 sprint(name, "lpt%d", i-1);
100 if(ioalloc(lptbase[i-1], 3, 0, name) < 0)
101 error("lpt port space in use");
102 lptallocd[i-1] = 1;
103 /* Detect ECP - if found, put into PS/2 mode to suit style of driver */
104 ecr = lptbase[i-1] + 0x402;
105 if ((inb(ecr) & 3) == 1) {
106 outb(ecr, 0x34);
107 if (inb(ecr) == 0x35) {
108 outb(ecr, (inb(ecr) & 0x1f) | (1 << 5));
109 if(ioalloc(ecr, 1, 0, name) < 0)
110 error("lpt ecr port space in use");
111 }
112 }
113 }
114 c = devattach('L', spec);
115 c->qid.path = Qdir;
116 c->dev = i-1;
117 return c;
118 }
119
120 static Walkqid*
121 lptwalk(Chan *c, Chan *nc, char **name, int nname)
122 {
123 return devwalk(c, nc, name, nname, lptdir, nelem(lptdir), lptgen);
124 }
125
126 static int
127 lptstat(Chan *c, uchar *dp, int n)
128 {
129 return devstat(c, dp, n, lptdir, nelem(lptdir), lptgen);
130 }
131
132 static Chan*
133 lptopen(Chan *c, int omode)
134 {
135 return devopen(c, omode, lptdir, nelem(lptdir), lptgen);
136 }
137
138 static void
139 lptclose(Chan *)
140 {
141 }
142
143 static long
144 lptread(Chan *c, void *a, long n, vlong)
145 {
146 char str[16];
147 int size;
148 ulong o;
149
150 if(c->qid.path == Qdir)
151 return devdirread(c, a, n, lptdir, nelem(lptdir), lptgen);
152 size = sprint(str, "0x%2.2ux\n", inb(c->qid.path));
153 o = c->offset;
154 if(o >= size)
155 return 0;
156 if(o+n > size)
157 n = size-c->offset;
158 memmove(a, str+o, n);
159 return n;
160 }
161
162 static long
163 lptwrite(Chan *c, void *a, long n, vlong)
164 {
165 char str[16], *p;
166 long base, k;
167
168 if(n <= 0)
169 return 0;
170 if(c->qid.path != Qdata){
171 if(n > sizeof str-1)
172 n = sizeof str-1;
173 memmove(str, a, n);
174 str[n] = 0;
175 outb(c->qid.path, strtoul(str, 0, 0));
176 return n;
177 }
178 p = a;
179 k = n;
180 base = lptbase[c->dev];
181 if(waserror()){
182 outb(base+Qpcr, Finitbar);
183 nexterror();
184 }
185 while(--k >= 0)
186 outch(base, *p++);
187 poperror();
188 return n;
189 }
190
191 static void
192 outch(int base, int c)
193 {
194 int status, tries;
195
196 for(tries=0;; tries++) {
197 status = inb(base+Qpsr);
198 if(status&Fnotbusy)
199 break;
200 if((status&Fpe)==0 && (status&(Fselect|Fnoerror)) != (Fselect|Fnoerror))
201 error(Eio);
202 outb(base+Qpcr, Finitbar|Fie);
203 tsleep(&lptrendez, lptready, (void *)base, 100);
204 }
205 outb(base+Qdlr, c);
206 outb(base+Qpcr, Finitbar|Fstrobe);
207 outb(base+Qpcr, Finitbar);
208 }
209
210 static int
211 lptready(void *base)
212 {
213 return inb((int)base+Qpsr)&Fnotbusy;
214 }
215
216 static void
217 lptintr(Ureg *, void *)
218 {
219 wakeup(&lptrendez);
220 }
221
222 Dev lptdevtab = {
223 'L',
224 "lpt",
225
226 devreset,
227 devinit,
228 devshutdown,
229 lptattach,
230 lptwalk,
231 lptstat,
232 lptopen,
233 devcreate,
234 lptclose,
235 lptread,
236 devbread,
237 lptwrite,
238 devbwrite,
239 devremove,
240 devwstat,
241 };
Cache object: 6b902f81811e24d8b06ba548c74b61d2
|