xref: /plan9-contrib/sys/src/9/pc/devlpt.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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