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 "../port/error.h"
7
#include "io.h"
8
 
9
enum{
10
	Linktarget = 0x13,
11
};
12
 
13
/*
14
 *  read and crack the card information structure enough to set
15
 *  important parameters like power
16
 */
17
/* cis memory walking */
18
typedef struct Cisdat {
19
	uchar	*cisbase;
20
	int	cispos;
21
	int	cisskip;
22
	int	cislen;
23
} Cisdat;
24
 
25
static void	tcfig(PCMslot*, Cisdat*, int);
26
static void	tentry(PCMslot*, Cisdat*, int);
27
static void	tvers1(PCMslot*, Cisdat*, int);
28
static void	tlonglnkmfc(PCMslot*, Cisdat*, int);
29
 
30
static int
31
readc(Cisdat *cis, uchar *x)
32
{
33
	if(cis->cispos >= cis->cislen)
34
		return 0;
35
	*x = cis->cisbase[cis->cisskip*cis->cispos];
36
	cis->cispos++;
37
	return 1;
38
}
39
 
40
static int
41
xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
42
{
43
	PCMmap *m;
44
	Cisdat cis;
45
	int i, l;
46
	uchar *p;
47
	uchar type, link, n, c;
48
	int this, subtype;
49
 
50
	m = pcmmap(slotno, 0, 0, attr);
51
	if(m == 0)
52
		return -1;
53
 
54
	cis.cisbase = KADDR(m->isa);
55
	cis.cispos = 0;
56
	cis.cisskip = attr ? 2 : 1;
57
	cis.cislen = m->len;
58
 
59
	/* loop through all the tuples */
60
	for(i = 0; i < 1000; i++){
61
		this = cis.cispos;
62
		if(readc(&cis, &type) != 1)
63
			break;
64
		if(type == 0xFF)
65
			break;
66
		if(readc(&cis, &link) != 1)
67
			break;
68
		if(link == 0xFF)
69
			break;
70
 
71
		n = link;
72
		if(link > 1 && subtuple != -1){
73
			if(readc(&cis, &c) != 1)
74
				break;
75
			subtype = c;
76
			n--;
77
		}else
78
			subtype = -1;
79
 
80
		if(type == tuple && subtype == subtuple){
81
			p = v;
82
			for(l=0; l<nv && l<n; l++)
83
				if(readc(&cis, p++) != 1)
84
					break;
85
			pcmunmap(slotno, m);
86
			return nv;
87
		}
88
		cis.cispos = this + (2+link);
89
	}
90
	pcmunmap(slotno, m);
91
	return -1;
92
}
93
 
94
int
95
pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
96
{
97
	int n;
98
 
99
	/* try attribute space, then memory */
100
	if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
101
		return n;
102
	return xcistuple(slotno, tuple, subtuple, v, nv, 0);
103
}
104
 
105
void
106
pcmcisread(PCMslot *pp)
107
{
108
	int this;
109
	Cisdat cis;
110
	PCMmap *m;
111
	uchar type, link;
112
 
113
	memset(pp->ctab, 0, sizeof(pp->ctab));
114
	pp->ncfg = 0;
115
	memset(pp->cfg, 0, sizeof(pp->cfg));
116
	pp->configed = 0;
117
	pp->nctab = 0;
118
	pp->verstr[0] = 0;
119
 
120
	/*
121
	 * Read all tuples in attribute space.
122
	 */
123
	m = pcmmap(pp->slotno, 0, 0, 1);
124
	if(m == 0)
125
		return;
126
 
127
	cis.cisbase = KADDR(m->isa);
128
	cis.cispos = 0;
129
	cis.cisskip = 2;
130
	cis.cislen = m->len;
131
 
132
	/* loop through all the tuples */
133
	for(;;){
134
		this = cis.cispos;
135
		if(readc(&cis, &type) != 1)
136
			break;
137
		if(type == 0xFF)
138
			break;
139
		if(readc(&cis, &link) != 1)
140
			break;
141
 
142
		switch(type){
143
		default:
144
			break;
145
		case 6:
146
			tlonglnkmfc(pp, &cis, type);
147
			break;
148
		case 0x15:
149
			tvers1(pp, &cis, type);
150
			break;
151
		case 0x1A:
152
			tcfig(pp, &cis, type);
153
			break;
154
		case 0x1B:
155
			tentry(pp, &cis, type);
156
			break;
157
		}
158
 
159
		if(link == 0xFF)
160
			break;
161
		cis.cispos = this + (2+link);
162
	}
163
	pcmunmap(pp->slotno, m);
164
}
165
 
166
static ulong
167
getlong(Cisdat *cis, int size)
168
{
169
	uchar c;
170
	int i;
171
	ulong x;
172
 
173
	x = 0;
174
	for(i = 0; i < size; i++){
175
		if(readc(cis, &c) != 1)
176
			break;
177
		x |= c<<(i*8);
178
	}
179
	return x;
180
}
181
 
182
static void
183
tcfig(PCMslot *pp, Cisdat *cis, int )
184
{
185
	uchar size, rasize, rmsize;
186
	uchar last;
187
 
188
	if(readc(cis, &size) != 1)
189
		return;
190
	rasize = (size&0x3) + 1;
191
	rmsize = ((size>>2)&0xf) + 1;
192
	if(readc(cis, &last) != 1)
193
		return;
194
 
195
	if(pp->ncfg >= 8){
196
		print("tcfig: too many configuration registers\n");
197
		return;
198
	}
199
 
200
	pp->cfg[pp->ncfg].caddr = getlong(cis, rasize);
201
	pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize);
202
	pp->ncfg++;
203
}
204
 
205
static ulong vexp[8] =
206
{
207
	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
208
};
209
static ulong vmant[16] =
210
{
211
	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
212
};
213
 
214
static ulong
215
microvolt(Cisdat *cis)
216
{
217
	uchar c;
218
	ulong microvolts;
219
	ulong exp;
220
 
221
	if(readc(cis, &c) != 1)
222
		return 0;
223
	exp = vexp[c&0x7];
224
	microvolts = vmant[(c>>3)&0xf]*exp;
225
	while(c & 0x80){
226
		if(readc(cis, &c) != 1)
227
			return 0;
228
		switch(c){
229
		case 0x7d:
230
			break;		/* high impedence when sleeping */
231
		case 0x7e:
232
		case 0x7f:
233
			microvolts = 0;	/* no connection */
234
			break;
235
		default:
236
			exp /= 10;
237
			microvolts += exp*(c&0x7f);
238
		}
239
	}
240
	return microvolts;
241
}
242
 
243
static ulong
244
nanoamps(Cisdat *cis)
245
{
246
	uchar c;
247
	ulong nanoamps;
248
 
249
	if(readc(cis, &c) != 1)
250
		return 0;
251
	nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
252
	while(c & 0x80){
253
		if(readc(cis, &c) != 1)
254
			return 0;
255
		if(c == 0x7d || c == 0x7e || c == 0x7f)
256
			nanoamps = 0;
257
	}
258
	return nanoamps;
259
}
260
 
261
/*
262
 * only nominal voltage (feature 1) is important for config,
263
 * other features must read card to stay in sync.
264
 */
265
static ulong
266
power(Cisdat *cis)
267
{
268
	uchar feature;
269
	ulong mv;
270
 
271
	mv = 0;
272
	if(readc(cis, &feature) != 1)
273
		return 0;
274
	if(feature & 1)
275
		mv = microvolt(cis);
276
	if(feature & 2)
277
		microvolt(cis);
278
	if(feature & 4)
279
		microvolt(cis);
280
	if(feature & 8)
281
		nanoamps(cis);
282
	if(feature & 0x10)
283
		nanoamps(cis);
284
	if(feature & 0x20)
285
		nanoamps(cis);
286
	if(feature & 0x40)
287
		nanoamps(cis);
288
	return mv/1000000;
289
}
290
 
291
static ulong mantissa[16] =
292
{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
293
 
294
static ulong exponent[8] =
295
{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
296
 
297
static ulong
298
ttiming(Cisdat *cis, int scale)
299
{
300
	uchar unscaled;
301
	ulong nanosecs;
302
 
303
	if(readc(cis, &unscaled) != 1)
304
		return 0;
305
	nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
306
	nanosecs = nanosecs * vexp[scale];
307
	return nanosecs;
308
}
309
 
310
static void
311
timing(Cisdat *cis, PCMconftab *ct)
312
{
313
	uchar c, i;
314
 
315
	if(readc(cis, &c) != 1)
316
		return;
317
	i = c&0x3;
318
	if(i != 3)
319
		ct->maxwait = ttiming(cis, i);		/* max wait */
320
	i = (c>>2)&0x7;
321
	if(i != 7)
322
		ct->readywait = ttiming(cis, i);		/* max ready/busy wait */
323
	i = (c>>5)&0x7;
324
	if(i != 7)
325
		ct->otherwait = ttiming(cis, i);		/* reserved wait */
326
}
327
 
328
static void
329
iospaces(Cisdat *cis, PCMconftab *ct)
330
{
331
	uchar c;
332
	int i, nio;
333
 
334
	ct->nio = 0;
335
	if(readc(cis, &c) != 1)
336
		return;
337
 
338
	ct->bit16 = ((c>>5)&3) >= 2;
339
	if(!(c & 0x80)){
340
		ct->io[0].start = 0;
341
		ct->io[0].len = 1<<(c&0x1f);
342
		ct->nio = 1;
343
		return;
344
	}
345
 
346
	if(readc(cis, &c) != 1)
347
		return;
348
 
349
	/*
350
	 * For each of the range descriptions read the
351
	 * start address and the length (value is length-1).
352
	 */
353
	nio = (c&0xf)+1;
354
	for(i = 0; i < nio; i++){
355
		ct->io[i].start = getlong(cis, (c>>4)&0x3);
356
		ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
357
	}
358
	ct->nio = nio;
359
}
360
 
361
static void
362
irq(Cisdat *cis, PCMconftab *ct)
363
{
364
	uchar c;
365
 
366
	if(readc(cis, &c) != 1)
367
		return;
368
	ct->irqtype = c & 0xe0;
369
	if(c & 0x10)
370
		ct->irqs = getlong(cis, 2);
371
	else
372
		ct->irqs = 1<<(c&0xf);
373
	ct->irqs &= 0xDEB8;		/* levels available to card */
374
}
375
 
376
static void
377
memspace(Cisdat *cis, int asize, int lsize, int host)
378
{
379
	ulong haddress, address, len;
380
 
381
	len = getlong(cis, lsize)*256;
382
	address = getlong(cis, asize)*256;
383
	USED(len, address);
384
	if(host){
385
		haddress = getlong(cis, asize)*256;
386
		USED(haddress);
387
	}
388
}
389
 
390
static void
391
tentry(PCMslot *pp, Cisdat *cis, int )
392
{
393
	uchar c, i, feature;
394
	PCMconftab *ct;
395
 
396
	if(pp->nctab >= nelem(pp->ctab))
397
		return;
398
	if(readc(cis, &c) != 1)
399
		return;
400
	ct = &pp->ctab[pp->nctab++];
401
 
402
	/* copy from last default config */
403
	if(pp->def)
404
		*ct = *pp->def;
405
 
406
	ct->index = c & 0x3f;
407
 
408
	/* is this the new default? */
409
	if(c & 0x40)
410
		pp->def = ct;
411
 
412
	/* memory wait specified? */
413
	if(c & 0x80){
414
		if(readc(cis, &i) != 1)
415
			return;
416
		if(i&0x80)
417
			ct->memwait = 1;
418
	}
419
 
420
	if(readc(cis, &feature) != 1)
421
		return;
422
	switch(feature&0x3){
423
	case 1:
424
		ct->vpp1 = ct->vpp2 = power(cis);
425
		break;
426
	case 2:
427
		power(cis);
428
		ct->vpp1 = ct->vpp2 = power(cis);
429
		break;
430
	case 3:
431
		power(cis);
432
		ct->vpp1 = power(cis);
433
		ct->vpp2 = power(cis);
434
		break;
435
	default:
436
		break;
437
	}
438
	if(feature&0x4)
439
		timing(cis, ct);
440
	if(feature&0x8)
441
		iospaces(cis, ct);
442
	if(feature&0x10)
443
		irq(cis, ct);
444
	switch((feature>>5)&0x3){
445
	case 1:
446
		memspace(cis, 0, 2, 0);
447
		break;
448
	case 2:
449
		memspace(cis, 2, 2, 0);
450
		break;
451
	case 3:
452
		if(readc(cis, &c) != 1)
453
			return;
454
		for(i = 0; i <= (c&0x7); i++)
455
			memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
456
		break;
457
	}
458
	pp->configed++;
459
}
460
 
461
static void
462
tvers1(PCMslot *pp, Cisdat *cis, int )
463
{
464
	uchar c, major, minor, last;
465
	int  i;
466
 
467
	if(readc(cis, &major) != 1)
468
		return;
469
	if(readc(cis, &minor) != 1)
470
		return;
471
	last = 0;
472
	for(i = 0; i < sizeof(pp->verstr)-1; i++){
473
		if(readc(cis, &c) != 1)
474
			return;
475
		if(c == 0)
476
			c = ';';
477
		if(c == '\n')
478
			c = ';';
479
		if(c == 0xff)
480
			break;
481
		if(c == ';' && last == ';')
482
			continue;
483
		pp->verstr[i] = c;
484
		last = c;
485
	}
486
	pp->verstr[i] = 0;
487
}
488
 
489
static void
490
tlonglnkmfc(PCMslot *pp, Cisdat *cis, int)
491
{
492
	int i, npos, opos;
493
	uchar nfn, space, expect, type, this, link;
494
 
495
	readc(cis, &nfn);
496
	for(i = 0; i < nfn; i++){
497
		readc(cis, &space);
498
		npos        = getlong(cis, 4);
499
		opos        = cis->cispos;
500
		cis->cispos = npos;
501
		expect      = Linktarget;
502
 
503
		while(1){
504
			this = cis->cispos;
505
			if(readc(cis, &type) != 1)
506
				break;
507
			if(type == 0xFF)
508
				break;
509
			if(readc(cis, &link) != 1)
510
				break;
511
 
512
			if(expect && expect != type){
513
				print("tlonglnkmfc: expected %X found %X\n",
514
					expect, type);
515
				break;
516
			}
517
			expect = 0;
518
 
519
			switch(type){
520
			default:
521
				break;
522
			case 0x15:
523
				tvers1(pp, cis, type);
524
				break;
525
			case 0x1A:
526
				tcfig(pp, cis, type);
527
				break;
528
			case 0x1B:
529
				tentry(pp, cis, type);
530
				break;
531
			}
532
 
533
			if(link == 0xFF)
534
				break;
535
			cis->cispos = this + (2+link);
536
		}
537
		cis->cispos = opos;
538
	}
539
}