Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
	snprint(up->genbuf, sizeof 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[8];
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
		snprint(name, sizeof 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 = snprint(str, sizeof 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
};