Subversion Repositories planix.SVN

Rev

Details | 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
typedef struct IOMap IOMap;
10
struct IOMap
11
{
12
	IOMap	*next;
13
	char	tag[13];
14
	ulong	start;
15
	ulong	end;
16
};
17
 
18
static struct
19
{
20
	Lock;
21
	IOMap	*m;
22
	IOMap	*free;
23
	IOMap	maps[32];		// some initial free maps
24
 
25
	QLock	ql;			// lock for reading map
26
} iomap;
27
 
28
enum {
29
	Qdir = 0,
30
	Qioalloc = 1,
31
	Qiob,
32
	Qiow,
33
	Qiol,
34
	Qbase,
35
 
36
	Qmax = 16,
37
};
38
 
39
typedef long Rdwrfn(Chan*, void*, long, vlong);
40
 
41
static Rdwrfn *readfn[Qmax];
42
static Rdwrfn *writefn[Qmax];
43
 
44
static Dirtab archdir[] = {
45
	".",	{ Qdir, 0, QTDIR },	0,	0555,
46
	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
47
	"iob",		{ Qiob, 0 },		0,	0660,
48
	"iow",		{ Qiow, 0 },		0,	0660,
49
	"iol",		{ Qiol, 0 },		0,	0660,
50
};
51
Lock archwlock;	/* the lock is only for changing archdir */
52
int narchdir = Qbase;
53
int (*_pcmspecial)(char *, ISAConf *);
54
void (*_pcmspecialclose)(int);
55
 
56
/*
57
 * Add a file to the #P listing.  Once added, you can't delete it.
58
 * You can't add a file with the same name as one already there,
59
 * and you get a pointer to the Dirtab entry so you can do things
60
 * like change the Qid version.  Changing the Qid path is disallowed.
61
 */
62
Dirtab*
63
addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
64
{
65
	int i;
66
	Dirtab d;
67
	Dirtab *dp;
68
 
69
	memset(&d, 0, sizeof d);
70
	strcpy(d.name, name);
71
	d.perm = perm;
72
 
73
	lock(&archwlock);
74
	if(narchdir >= Qmax){
75
		unlock(&archwlock);
76
		return nil;
77
	}
78
 
79
	for(i=0; i<narchdir; i++)
80
		if(strcmp(archdir[i].name, name) == 0){
81
			unlock(&archwlock);
82
			return nil;
83
		}
84
 
85
	d.qid.path = narchdir;
86
	archdir[narchdir] = d;
87
	readfn[narchdir] = rdfn;
88
	writefn[narchdir] = wrfn;
89
	dp = &archdir[narchdir++];
90
	unlock(&archwlock);
91
 
92
	return dp;
93
}
94
 
95
void
96
ioinit(void)
97
{
98
	int i;
99
 
100
	for(i = 0; i < nelem(iomap.maps)-1; i++)
101
		iomap.maps[i].next = &iomap.maps[i+1];
102
	iomap.maps[i].next = nil;
103
	iomap.free = iomap.maps;
104
 
105
	// a dummy entry at 2^17
106
	ioalloc(0x20000, 1, 0, "dummy");
107
}
108
 
109
//
110
//	alloc some io port space and remember who it was
111
//	alloced to.  if port < 0, find a free region.
112
//
113
int
114
ioalloc(int port, int size, int align, char *tag)
115
{
116
	IOMap *m, **l;
117
	int i;
118
 
119
	lock(&iomap);
120
	if(port < 0){
121
		// find a free port above 0x400 and below 0x1000
122
		port = 0x400;
123
		for(l = &iomap.m; *l; l = &(*l)->next){
124
			m = *l;
125
			i = m->start - port;
126
			if(i > size)
127
				break;
128
			if(align > 0)
129
				port = ((port+align-1)/align)*align;
130
			else
131
				port = m->end;
132
		}
133
		if(*l == nil){
134
			unlock(&iomap);
135
			return -1;
136
		}
137
	} else {
138
		// see if the space clashes with previously allocated ports
139
		for(l = &iomap.m; *l; l = &(*l)->next){
140
			m = *l;
141
			if(m->end <= port)
142
				continue;
143
			if(m->start >= port+size)
144
				break;
145
			unlock(&iomap);
146
			return -1;
147
		}
148
	}
149
	m = iomap.free;
150
	if(m == nil){
151
		print("ioalloc: out of maps");
152
		unlock(&iomap);
153
		return port;
154
	}
155
	iomap.free = m->next;
156
	m->next = *l;
157
	m->start = port;
158
	m->end = port + size;
159
	strncpy(m->tag, tag, sizeof(m->tag));
160
	m->tag[sizeof(m->tag)-1] = 0;
161
	*l = m;
162
 
163
	archdir[0].qid.vers++;
164
 
165
	unlock(&iomap);
166
	return m->start;
167
}
168
 
169
void
170
iofree(int port)
171
{
172
	IOMap *m, **l;
173
 
174
	lock(&iomap);
175
	for(l = &iomap.m; *l; l = &(*l)->next){
176
		if((*l)->start == port){
177
			m = *l;
178
			*l = m->next;
179
			m->next = iomap.free;
180
			iomap.free = m;
181
			break;
182
		}
183
		if((*l)->start > port)
184
			break;
185
	}
186
	archdir[0].qid.vers++;
187
	unlock(&iomap);
188
}
189
 
190
int
191
iounused(int start, int end)
192
{
193
	IOMap *m;
194
 
195
	for(m = iomap.m; m; m = m->next){
196
		if(start >= m->start && start < m->end
197
		|| start <= m->start && end > m->start)
198
			return 0; 
199
	}
200
	return 1;
201
}
202
 
203
static void
204
checkport(int start, int end)
205
{
206
	/* standard vga regs are OK */
207
	if(start >= 0x2b0 && end <= 0x2df+1)
208
		return;
209
	if(start >= 0x3c0 && end <= 0x3da+1)
210
		return;
211
 
212
	if(iounused(start, end))
213
		return;
214
	error(Eperm);
215
}
216
 
217
static Chan*
218
archattach(char* spec)
219
{
220
	return devattach('P', spec);
221
}
222
 
223
Walkqid*
224
archwalk(Chan* c, Chan *nc, char** name, int nname)
225
{
226
	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
227
}
228
 
229
static int
230
archstat(Chan* c, uchar* dp, int n)
231
{
232
	return devstat(c, dp, n, archdir, narchdir, devgen);
233
}
234
 
235
static Chan*
236
archopen(Chan* c, int omode)
237
{
238
	return devopen(c, omode, archdir, nelem(archdir), devgen);
239
}
240
 
241
static void
242
archclose(Chan*)
243
{
244
}
245
 
246
enum
247
{
248
	Linelen= 31,
249
};
250
 
251
static long
252
archread(Chan *c, void *a, long n, vlong offset)
253
{
254
	char buf[Linelen+1], *p;
255
	int port;
256
	ushort *sp;
257
	ulong *lp;
258
	IOMap *m;
259
	Rdwrfn *fn;
260
 
261
	switch((ulong)c->qid.path){
262
 
263
	case Qdir:
264
		return devdirread(c, a, n, archdir, nelem(archdir), devgen);
265
 
266
	case Qiob:
267
		port = offset;
268
		checkport(offset, offset+n);
269
		for(p = a; port < offset+n; port++)
270
			*p++ = inb(port);
271
		return n;
272
 
273
	case Qiow:
274
		if((n & 0x01) || (offset & 0x01))
275
			error(Ebadarg);
276
		checkport(offset, offset+n+1);
277
		n /= 2;
278
		sp = a;
279
		for(port = offset; port < offset+n; port += 2)
280
			*sp++ = ins(port);
281
		return n*2;
282
 
283
	case Qiol:
284
		if((n & 0x03) || (offset & 0x03))
285
			error(Ebadarg);
286
		checkport(offset, offset+n+3);
287
		n /= 4;
288
		lp = a;
289
		for(port = offset; port < offset+n; port += 4)
290
			*lp++ = inl(port);
291
		return n*4;
292
 
293
	case Qioalloc:
294
		break;
295
 
296
	default:
297
		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
298
			return fn(c, a, n, offset);
299
		error(Eperm);
300
		break;
301
	}
302
 
303
	offset = offset/Linelen;
304
	n = n/Linelen;
305
	p = a;
306
	lock(&iomap);
307
	for(m = iomap.m; n > 0 && m != nil; m = m->next){
308
		if(offset-- > 0)
309
			continue;
310
		if(strcmp(m->tag, "dummy") == 0)
311
			break;
312
		sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
313
		memmove(p, buf, Linelen);
314
		p += Linelen;
315
		n--;
316
	}
317
	unlock(&iomap);
318
 
319
	return p - (char*)a;
320
}
321
 
322
static long
323
archwrite(Chan *c, void *a, long n, vlong offset)
324
{
325
	char *p;
326
	int port;
327
	ushort *sp;
328
	ulong *lp;
329
	Rdwrfn *fn;
330
 
331
	switch((ulong)c->qid.path){
332
 
333
	case Qiob:
334
		p = a;
335
		checkport(offset, offset+n);
336
		for(port = offset; port < offset+n; port++)
337
			outb(port, *p++);
338
		return n;
339
 
340
	case Qiow:
341
		if((n & 01) || (offset & 01))
342
			error(Ebadarg);
343
		checkport(offset, offset+n+1);
344
		n /= 2;
345
		sp = a;
346
		for(port = offset; port < offset+n; port += 2)
347
			outs(port, *sp++);
348
		return n*2;
349
 
350
	case Qiol:
351
		if((n & 0x03) || (offset & 0x03))
352
			error(Ebadarg);
353
		checkport(offset, offset+n+3);
354
		n /= 4;
355
		lp = a;
356
		for(port = offset; port < offset+n; port += 4)
357
			outl(port, *lp++);
358
		return n*4;
359
 
360
	default:
361
		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
362
			return fn(c, a, n, offset);
363
		error(Eperm);
364
		break;
365
	}
366
	return 0;
367
}
368
 
369
Dev archdevtab = {
370
	'P',
371
	"arch",
372
 
373
	devreset,
374
	devinit,
375
	devshutdown,
376
	archattach,
377
	archwalk,
378
	archstat,
379
	archopen,
380
	devcreate,
381
	archclose,
382
	archread,
383
	devbread,
384
	archwrite,
385
	devbwrite,
386
	devremove,
387
	devwstat,
388
};
389
 
390
int
391
pcmspecial(char *idstr, ISAConf *isa)
392
{
393
	return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
394
}
395
 
396
void
397
pcmspecialclose(int a)
398
{
399
	if (_pcmspecialclose != nil)
400
		_pcmspecialclose(a);
401
}