Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 *	ISA PNP 1.0 support + access to PCI configuration space
3
 *
4
 *	TODO
5
 *		- implement PNP card configuration (setting io bases etc)
6
 *		- write user program to drive PNP configuration...
7
 *		- extend PCI raw access to configuration space (writes, byte/short access?)
8
 *		- implement PCI access to memory/io space/BIOS ROM
9
 *		- use c->aux instead of performing lookup on each read/write?
10
 */
11
#include	"u.h"
12
#include	"../port/lib.h"
13
#include	"mem.h"
14
#include	"dat.h"
15
#include	"fns.h"
16
#include	"io.h"
17
#include	"../port/error.h"
18
 
19
typedef struct Pnp Pnp;
20
typedef struct Card Card;
21
 
22
struct Pnp
23
{
24
	QLock;
25
	int		rddata;
26
	int		debug;
27
	Card		*cards;
28
};
29
 
30
struct Card
31
{
32
	int		csn;
33
	ulong	id1;
34
	ulong	id2;
35
	char		*cfgstr;
36
	int		ncfg;
37
	Card*	next;
38
};
39
 
40
static Pnp	pnp;
41
 
42
#define	DPRINT	if(pnp.debug) print
43
#define	XPRINT	if(1) print
44
 
45
enum {
46
	Address = 0x279,
47
	WriteData = 0xa79,
48
 
49
	Qtopdir = 0,
50
 
51
	Qpnpdir,
52
	Qpnpctl,
53
	Qcsnctl,
54
	Qcsnraw,
55
 
56
	Qpcidir,
57
	Qpcictl,
58
	Qpciraw,
59
};
60
 
61
#define TYPE(q)		((ulong)(q).path & 0x0F)
62
#define CSN(q)		(((ulong)(q).path>>4) & 0xFF)
63
#define QID(c, t)	(((c)<<4)|(t))
64
 
65
static Dirtab topdir[] = {
66
	".",	{ Qtopdir, 0, QTDIR },	0,	0555,
67
	"pnp",	{ Qpnpdir, 0, QTDIR },	0,	0555,
68
	"pci",	{ Qpcidir, 0, QTDIR },	0,	0555,
69
};
70
 
71
static Dirtab pnpdir[] = {
72
	".",	{ Qpnpdir, 0, QTDIR },	0,	0555,
73
	"ctl",	{ Qpnpctl, 0, 0 },	0,	0666,
74
};
75
 
76
extern Dev pnpdevtab;
77
static int wrconfig(Card*, char*);
78
 
79
static char key[32] =
80
{
81
	0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
82
	0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
83
	0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
84
	0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39,
85
};
86
 
87
static void
88
cmd(int reg, int val)
89
{
90
	outb(Address, reg);
91
	outb(WriteData, val);
92
}
93
 
94
/* Send initiation key, putting each card in Sleep state */
95
static void
96
initiation(void)
97
{
98
	int i;
99
 
100
	/* ensure each card's LFSR is reset */
101
	outb(Address, 0x00);
102
	outb(Address, 0x00);
103
 
104
	/* send initiation key */
105
	for (i = 0; i < 32; i++)
106
		outb(Address, key[i]);
107
}
108
 
109
/* isolation protocol... */
110
static int
111
readbit(int rddata)
112
{
113
	int r1, r2;
114
 
115
	r1 = inb(rddata);
116
	r2 = inb(rddata);
117
	microdelay(250);
118
	return (r1 == 0x55) && (r2 == 0xaa);
119
}
120
 
121
static int
122
isolate(int rddata, ulong *id1, ulong *id2)
123
{
124
	int i, csum, bit;
125
	uchar *p, id[9];
126
 
127
	outb(Address, 0x01);	/* point to serial isolation register */
128
	delay(1);
129
	csum = 0x6a;
130
	for(i = 0; i < 64; i++){
131
		bit = readbit(rddata);
132
		csum = (csum>>1) | (((csum&1) ^ ((csum>>1)&1) ^ bit)<<7);
133
		p = &id[i>>3];
134
		*p = (*p>>1) | (bit<<7);
135
	}
136
	for(; i < 72; i++){
137
		p = &id[i>>3];
138
		*p = (*p>>1) | (readbit(rddata)<<7);
139
	}
140
	*id1 = (id[3]<<24)|(id[2]<<16)|(id[1]<<8)|id[0];
141
	*id2 = (id[7]<<24)|(id[6]<<16)|(id[5]<<8)|id[4];
142
	if(*id1 == 0)
143
		return 0;
144
	if(id[8] != csum)
145
		DPRINT("pnp: bad checksum id1 %lux id2 %lux csum %x != %x\n", *id1, *id2, csum, id[8]); /**/
146
	return id[8] == csum;
147
}
148
 
149
static int
150
getresbyte(int rddata)
151
{
152
	int tries = 0;
153
 
154
	outb(Address, 0x05);
155
	while ((inb(rddata) & 1) == 0)
156
		if (tries++ > 1000000)
157
			error("pnp: timeout waiting for resource data\n");
158
	outb(Address, 0x04);
159
	return inb(rddata);
160
}
161
 
162
static char *
163
serial(ulong id1, ulong id2)
164
{
165
	int i1, i2, i3;
166
	ulong x;
167
	static char buf[20];
168
 
169
	i1 = (id1>>2)&31;
170
	i2 = ((id1<<3)&24)+((id1>>13)&7);
171
	i3 = (id1>>8)&31;
172
	x = (id1>>8)&0xff00|(id1>>24)&0x00ff;
173
	if (i1 > 0 && i1 < 27 && i2 > 0 && i2 < 27 && i3 > 0 && i3 < 27 && (id1 & (1<<7)) == 0)
174
		snprint(buf, sizeof(buf), "%c%c%c%.4lux.%lux", 'A'+i1-1, 'A'+i2-1, 'A'+i3-1, x, id2);
175
	else
176
		snprint(buf, sizeof(buf), "%.4lux%.4lux.%lux", (id1<<8)&0xff00|(id1>>8)&0x00ff, x, id2);
177
	return buf;
178
}
179
 
180
static Card *
181
findcsn(int csn, int create, int dolock)
182
{
183
	Card *c, *nc, **l;
184
 
185
	if(dolock)
186
		qlock(&pnp);
187
	l = &pnp.cards;
188
	for(c = *l; c != nil; c = *l) {
189
		if(c->csn == csn)
190
			goto done;
191
		if(c->csn > csn)
192
			break;
193
		l = &c->next;
194
	}
195
	if(create) {
196
		*l = nc = malloc(sizeof(Card));
197
		if(nc == nil) {
198
			if(dolock)
199
				qunlock(&pnp);
200
			error(Enomem);
201
		}
202
		nc->next = c;
203
		nc->csn = csn;
204
		c = nc;
205
	}
206
done:
207
	if(dolock)
208
		qunlock(&pnp);
209
	return c;
210
}
211
 
212
static int
213
newcsn(void)
214
{
215
	int csn;
216
	Card *c;
217
 
218
	csn = 1;
219
	for(c = pnp.cards; c != nil; c = c->next) {
220
		if(c->csn > csn)
221
			break;
222
		csn = c->csn+1;
223
	}
224
	return csn;
225
}
226
 
227
static int
228
pnpncfg(int rddata)
229
{
230
	int i, n, x, ncfg, n1, n2;
231
 
232
	ncfg = 0;
233
	for (;;) {
234
		x = getresbyte(rddata);
235
		if((x & 0x80) == 0) {
236
			n = (x&7)+1;
237
			for(i = 1; i < n; i++)
238
				getresbyte(rddata);
239
		}
240
		else {
241
			n1 = getresbyte(rddata);
242
			n2 = getresbyte(rddata);
243
			n = (n2<<8)|n1 + 3;
244
			for (i = 3; i < n; i++)
245
				getresbyte(rddata);
246
		}
247
		ncfg += n;
248
		if((x>>3) == 0x0f)
249
			break;
250
	}
251
	return ncfg;
252
}
253
 
254
/* look for cards, and assign them CSNs */
255
static int
256
pnpscan(int rddata, int dawn)
257
{
258
	Card *c;
259
	int csn;
260
	ulong id1, id2;
261
 
262
	initiation();				/* upsilon sigma */
263
	cmd(0x02, 0x04+0x01);		/* reset CSN on all cards and reset logical devices */
264
	delay(1);					/* delay after resetting cards */
265
 
266
	cmd(0x03, 0);				/* Wake all cards with a CSN of 0 */
267
	cmd(0x00, rddata>>2);		/* Set the READ_DATA port on all cards */
268
	while(isolate(rddata, &id1, &id2)) {
269
		for(c = pnp.cards; c != nil; c = c->next)
270
			if(c->id1 == id1 && c->id2 == id2)
271
				break;
272
		if(c == nil) {
273
			csn = newcsn();
274
			c = findcsn(csn, 1, 0);
275
			c->id1 = id1;
276
			c->id2 = id2;
277
		}
278
		else if(c->cfgstr != nil) {
279
			if(!wrconfig(c, c->cfgstr))
280
				print("pnp%d: bad cfg: %s\n", c->csn, c->cfgstr);
281
			c->cfgstr = nil;
282
		}
283
		cmd(0x06, c->csn);		/* set the card's csn */
284
		if(dawn)
285
			print("pnp%d: %s\n", c->csn, serial(id1, id2));
286
		c->ncfg = pnpncfg(rddata);
287
		cmd(0x03, 0);		/* Wake all cards with a CSN of 0, putting this card to sleep */
288
	}
289
	cmd(0x02, 0x02);			/* return cards to Wait for Key state */
290
	if(pnp.cards != 0) {
291
		pnp.rddata = rddata;
292
		return 1;
293
	}
294
	return 0;
295
}
296
 
297
static void
298
pnpreset(void)
299
{
300
	Card *c;
301
	ulong id1, id2;
302
	int csn, i1, i2, i3, x;
303
	char *s, *p, buf[20];
304
	ISAConf isa;
305
 
306
	memset(&isa, 0, sizeof(ISAConf));
307
	pnp.rddata = -1;
308
	if (isaconfig("pnp", 0, &isa) == 0)
309
		return;
310
	if(isa.port < 0x203 || isa.port > 0x3ff)
311
		return;
312
	for(csn = 1; csn < 256; csn++) {
313
		snprint(buf, sizeof buf, "pnp%d", csn);
314
		s = getconf(buf);
315
		if(s == 0)
316
			continue;
317
		if(strlen(s) < 8 || s[7] != '.' || s[0] < 'A' || s[0] > 'Z' || s[1] < 'A' || s[1] > 'Z' || s[2] < 'A' || s[2] > 'Z') {
318
bad:
319
			print("pnp%d: bad conf string %s\n", csn, s);
320
			continue;	
321
		}
322
		i1 = s[0]-'A'+1;
323
		i2 = s[1]-'A'+1;
324
		i3 = s[2]-'A'+1;
325
		x = strtoul(&s[3], 0, 16);
326
		id1 = (i1<<2)|((i2>>3)&3)|((i2&7)<<13)|(i3<<8)|((x&0xff)<<24)|((x&0xff00)<<8);
327
		id2 = strtoul(&s[8], &p, 16);
328
		if(*p == ' ')
329
			p++;
330
		else if(*p == '\0')
331
			p = nil;
332
		else
333
			goto bad;
334
		c = findcsn(csn, 1, 0);
335
		c->id1 = id1;
336
		c->id2 = id2;
337
		c->cfgstr = p;
338
	}
339
	pnpscan(isa.port, 1);
340
}
341
 
342
static int
343
csngen(Chan *c, int t, int csn, Card *cp, Dir *dp)
344
{
345
	Qid q;
346
 
347
	switch(t) {
348
	case Qcsnctl:
349
		q = (Qid){QID(csn, Qcsnctl), 0, 0};
350
		snprint(up->genbuf, sizeof up->genbuf, "csn%dctl", csn);
351
		devdir(c, q, up->genbuf, 0, eve, 0664, dp);
352
		return 1;
353
	case Qcsnraw:
354
		q = (Qid){QID(csn, Qcsnraw), 0, 0};
355
		snprint(up->genbuf, sizeof up->genbuf, "csn%draw", csn);
356
		devdir(c, q, up->genbuf, cp->ncfg, eve, 0444, dp);
357
		return 1;
358
	}
359
	return -1;
360
}
361
 
362
static int
363
pcigen(Chan *c, int t, int tbdf, Dir *dp)
364
{
365
	Qid q;
366
 
367
	q = (Qid){BUSBDF(tbdf)|t, 0, 0};
368
	switch(t) {
369
	case Qpcictl:
370
		snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%dctl",
371
			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
372
		devdir(c, q, up->genbuf, 0, eve, 0444, dp);
373
		return 1;
374
	case Qpciraw:
375
		snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%draw",
376
			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
377
		devdir(c, q, up->genbuf, 128, eve, 0660, dp);
378
		return 1;
379
	}
380
	return -1;
381
}
382
 
383
static int
384
pnpgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
385
{
386
	Qid q;
387
	Card *cp;
388
	Pcidev *p;
389
	int csn, tbdf;
390
 
391
	switch(TYPE(c->qid)){
392
	case Qtopdir:
393
		if(s == DEVDOTDOT){
394
			q = (Qid){QID(0, Qtopdir), 0, QTDIR};
395
			snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
396
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
397
			return 1;
398
		}
399
		return devgen(c, nil, topdir, nelem(topdir), s, dp);
400
	case Qpnpdir:
401
		if(s == DEVDOTDOT){
402
			q = (Qid){QID(0, Qtopdir), 0, QTDIR};
403
			snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
404
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
405
			return 1;
406
		}
407
		if(s < nelem(pnpdir)-1)
408
			return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
409
		s -= nelem(pnpdir)-1;
410
		qlock(&pnp);
411
		cp = pnp.cards;
412
		while(s >= 2 && cp != nil) {
413
			s -= 2;
414
			cp = cp->next;
415
		}
416
		qunlock(&pnp);
417
		if(cp == nil)
418
			return -1;
419
		return csngen(c, s+Qcsnctl, cp->csn, cp, dp);
420
	case Qpnpctl:
421
		return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
422
	case Qcsnctl:
423
	case Qcsnraw:
424
		csn = CSN(c->qid);
425
		cp = findcsn(csn, 0, 1);
426
		if(cp == nil)
427
			return -1;
428
		return csngen(c, TYPE(c->qid), csn, cp, dp);
429
	case Qpcidir:
430
		if(s == DEVDOTDOT){
431
			q = (Qid){QID(0, Qtopdir), 0, QTDIR};
432
			snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
433
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
434
			return 1;
435
		}
436
		p = pcimatch(nil, 0, 0);
437
		while(s >= 2 && p != nil) {
438
			p = pcimatch(p, 0, 0);
439
			s -= 2;
440
		}
441
		if(p == nil)
442
			return -1;
443
		return pcigen(c, s+Qpcictl, p->tbdf, dp);
444
	case Qpcictl:
445
	case Qpciraw:
446
		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
447
		p = pcimatchtbdf(tbdf);
448
		if(p == nil)
449
			return -1;
450
		return pcigen(c, TYPE(c->qid), tbdf, dp);
451
	default:
452
		break;
453
	}
454
	return -1;
455
}
456
 
457
static Chan*
458
pnpattach(char *spec)
459
{
460
	return devattach(pnpdevtab.dc, spec);
461
}
462
 
463
Walkqid*
464
pnpwalk(Chan* c, Chan *nc, char** name, int nname)
465
{
466
	return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pnpgen);
467
}
468
 
469
static int
470
pnpstat(Chan* c, uchar* dp, int n)
471
{
472
	return devstat(c, dp, n, (Dirtab *)0, 0L, pnpgen);
473
}
474
 
475
static Chan*
476
pnpopen(Chan *c, int omode)
477
{
478
	c = devopen(c, omode, (Dirtab*)0, 0, pnpgen);
479
	switch(TYPE(c->qid)){
480
	default:
481
		break;
482
	}
483
	return c;
484
}
485
 
486
static void
487
pnpclose(Chan*)
488
{
489
}
490
 
491
static long
492
pnpread(Chan *c, void *va, long n, vlong offset)
493
{
494
	ulong x;
495
	Card *cp;
496
	Pcidev *p;
497
	char buf[256], *ebuf, *w;
498
	char *a = va;
499
	int csn, i, tbdf, r;
500
 
501
	switch(TYPE(c->qid)){
502
	case Qtopdir:
503
	case Qpnpdir:
504
	case Qpcidir:
505
		return devdirread(c, a, n, (Dirtab *)0, 0L, pnpgen);
506
	case Qpnpctl:
507
		if(pnp.rddata > 0)
508
			snprint(up->genbuf, sizeof up->genbuf, "enabled %#x\n",
509
				pnp.rddata);
510
		else
511
			snprint(up->genbuf, sizeof up->genbuf, "disabled\n");
512
		return readstr(offset, a, n, up->genbuf);
513
	case Qcsnraw:
514
		csn = CSN(c->qid);
515
		cp = findcsn(csn, 0, 1);
516
		if(cp == nil)
517
			error(Egreg);
518
		if(offset+n > cp->ncfg)
519
			n = cp->ncfg - offset;
520
		qlock(&pnp);
521
		initiation();
522
		cmd(0x03, csn);				/* Wake up the card */
523
		for(i = 0; i < offset+9; i++)		/* 9 == skip serial + csum */
524
			getresbyte(pnp.rddata);
525
		for(i = 0; i < n; i++)
526
			a[i] = getresbyte(pnp.rddata);
527
		cmd(0x03, 0);					/* Wake all cards with a CSN of 0, putting this card to sleep */
528
		cmd(0x02, 0x02);				/* return cards to Wait for Key state */
529
		qunlock(&pnp);
530
		break;
531
	case Qcsnctl:
532
		csn = CSN(c->qid);
533
		cp = findcsn(csn, 0, 1);
534
		if(cp == nil)
535
			error(Egreg);
536
		snprint(up->genbuf, sizeof up->genbuf, "%s\n",
537
			serial(cp->id1, cp->id2));
538
		return readstr(offset, a, n, up->genbuf);
539
	case Qpcictl:
540
		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
541
		p = pcimatchtbdf(tbdf);
542
		if(p == nil)
543
			error(Egreg);
544
		ebuf = buf+sizeof buf-1;	/* -1 for newline */
545
		w = seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
546
			p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);
547
		for(i=0; i<nelem(p->mem); i++){
548
			if(p->mem[i].size == 0)
549
				continue;
550
			w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
551
		}
552
		*w++ = '\n';
553
		*w = '\0';
554
		return readstr(offset, a, n, buf);
555
	case Qpciraw:
556
		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
557
		p = pcimatchtbdf(tbdf);
558
		if(p == nil)
559
			error(Egreg);
560
		if(offset > 256)
561
			return 0;
562
		if(n+offset > 256)
563
			n = 256-offset;
564
		r = offset;
565
		if(!(r & 3) && n == 4){
566
			x = pcicfgr32(p, r);
567
			PBIT32(a, x);
568
			return 4;
569
		}
570
		if(!(r & 1) && n == 2){
571
			x = pcicfgr16(p, r);
572
			PBIT16(a, x);
573
			return 2;
574
		}
575
		for(i = 0; i <  n; i++){
576
			x = pcicfgr8(p, r);
577
			PBIT8(a, x);
578
			a++;
579
			r++;
580
		}
581
		return i;
582
	default:
583
		error(Egreg);
584
	}
585
	return n;
586
}
587
 
588
static long
589
pnpwrite(Chan *c, void *va, long n, vlong offset)
590
{
591
	Card *cp;
592
	Pcidev *p;
593
	ulong port, x;
594
	char buf[256];
595
	uchar *a;
596
	int csn, i, r, tbdf;
597
 
598
	if(n >= sizeof(buf))
599
		n = sizeof(buf)-1;
600
	a = va;
601
	strncpy(buf, va, n);
602
	buf[n] = 0;
603
 
604
	switch(TYPE(c->qid)){
605
	case Qpnpctl:
606
		if(strncmp(buf, "port ", 5) == 0) {
607
			port = strtoul(buf+5, 0, 0);
608
			if(port < 0x203 || port > 0x3ff)
609
				error("bad value for rddata port");
610
			qlock(&pnp);
611
			if(waserror()) {
612
				qunlock(&pnp);
613
				nexterror();
614
			}
615
			if(pnp.rddata > 0)
616
				error("pnp port already set");
617
			if(!pnpscan(port, 0))
618
				error("no cards found");
619
			qunlock(&pnp);
620
			poperror();
621
		}
622
		else if(strncmp(buf, "debug ", 6) == 0)
623
			pnp.debug = strtoul(buf+6, 0, 0);
624
		else
625
			error(Ebadctl);
626
		break;
627
	case Qcsnctl:
628
		csn = CSN(c->qid);
629
		cp = findcsn(csn, 0, 1);
630
		if(cp == nil)
631
			error(Egreg);
632
		if(!wrconfig(cp, buf))
633
			error(Ebadctl);
634
		break;
635
	case Qpciraw:
636
		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
637
		p = pcimatchtbdf(tbdf);
638
		if(p == nil)
639
			error(Egreg);
640
		if(offset > 256)
641
			return 0;
642
		if(n+offset > 256)
643
			n = 256-offset;
644
		r = offset;
645
		if(!(r & 3) && n == 4){
646
			x = GBIT32(a);
647
			pcicfgw32(p, r, x);
648
			return 4;
649
		}
650
		if(!(r & 1) && n == 2){
651
			x = GBIT16(a);
652
			pcicfgw16(p, r, x);
653
			return 2;
654
		}
655
		for(i = 0; i <  n; i++){
656
			x = GBIT8(a);
657
			pcicfgw8(p, r, x);
658
			a++;
659
			r++;
660
		}
661
		return i;
662
	default:
663
		error(Egreg);
664
	}
665
	return n;
666
}
667
 
668
static int
669
wrconfig(Card *c, char *cmd)
670
{
671
	/* This should implement setting of I/O bases, etc */
672
	USED(c, cmd);
673
	return 1;
674
}
675
 
676
 
677
Dev pnpdevtab = {
678
	'$',
679
	"pnp",
680
 
681
	pnpreset,
682
	devinit,
683
	devshutdown,
684
	pnpattach,
685
	pnpwalk,
686
	pnpstat,
687
	pnpopen,
688
	devcreate,
689
	pnpclose,
690
	pnpread,
691
	devbread,
692
	pnpwrite,
693
	devbwrite,
694
	devremove,
695
	devwstat,
696
};