xref: /plan9/sys/src/9/port/cis.c (revision 1517423268547a2c0be806559a31cb95653443d5)
180ee5cbfSDavid du Colombier #include "u.h"
280ee5cbfSDavid du Colombier #include "../port/lib.h"
380ee5cbfSDavid du Colombier #include "mem.h"
480ee5cbfSDavid du Colombier #include "dat.h"
580ee5cbfSDavid du Colombier #include "fns.h"
680ee5cbfSDavid du Colombier #include "../port/error.h"
780ee5cbfSDavid du Colombier #include "io.h"
880ee5cbfSDavid du Colombier 
9*15174232SDavid du Colombier enum{
10*15174232SDavid du Colombier 	Linktarget = 0x13,
11*15174232SDavid du Colombier };
12*15174232SDavid du Colombier 
1380ee5cbfSDavid du Colombier /*
1480ee5cbfSDavid du Colombier  *  read and crack the card information structure enough to set
1580ee5cbfSDavid du Colombier  *  important parameters like power
1680ee5cbfSDavid du Colombier  */
179a747e4fSDavid du Colombier /* cis memory walking */
189a747e4fSDavid du Colombier typedef struct Cisdat {
199a747e4fSDavid du Colombier 	uchar	*cisbase;
209a747e4fSDavid du Colombier 	int	cispos;
219a747e4fSDavid du Colombier 	int	cisskip;
229a747e4fSDavid du Colombier 	int	cislen;
239a747e4fSDavid du Colombier } Cisdat;
249a747e4fSDavid du Colombier 
2580ee5cbfSDavid du Colombier static void	tcfig(PCMslot*, Cisdat*, int);
2680ee5cbfSDavid du Colombier static void	tentry(PCMslot*, Cisdat*, int);
2780ee5cbfSDavid du Colombier static void	tvers1(PCMslot*, Cisdat*, int);
28*15174232SDavid du Colombier static void	tlonglnkmfc(PCMslot*, Cisdat*, int);
2980ee5cbfSDavid du Colombier 
3080ee5cbfSDavid du Colombier static int
readc(Cisdat * cis,uchar * x)319a747e4fSDavid du Colombier readc(Cisdat *cis, uchar *x)
3280ee5cbfSDavid du Colombier {
339a747e4fSDavid du Colombier 	if(cis->cispos >= cis->cislen)
3480ee5cbfSDavid du Colombier 		return 0;
359a747e4fSDavid du Colombier 	*x = cis->cisbase[cis->cisskip*cis->cispos];
369a747e4fSDavid du Colombier 	cis->cispos++;
3780ee5cbfSDavid du Colombier 	return 1;
3880ee5cbfSDavid du Colombier }
3980ee5cbfSDavid du Colombier 
4080ee5cbfSDavid du Colombier static int
xcistuple(int slotno,int tuple,int subtuple,void * v,int nv,int attr)4180ee5cbfSDavid du Colombier xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
4280ee5cbfSDavid du Colombier {
4380ee5cbfSDavid du Colombier 	PCMmap *m;
4480ee5cbfSDavid du Colombier 	Cisdat cis;
4580ee5cbfSDavid du Colombier 	int i, l;
4680ee5cbfSDavid du Colombier 	uchar *p;
4780ee5cbfSDavid du Colombier 	uchar type, link, n, c;
4880ee5cbfSDavid du Colombier 	int this, subtype;
4980ee5cbfSDavid du Colombier 
5080ee5cbfSDavid du Colombier 	m = pcmmap(slotno, 0, 0, attr);
5180ee5cbfSDavid du Colombier 	if(m == 0)
5280ee5cbfSDavid du Colombier 		return -1;
5380ee5cbfSDavid du Colombier 
5480ee5cbfSDavid du Colombier 	cis.cisbase = KADDR(m->isa);
5580ee5cbfSDavid du Colombier 	cis.cispos = 0;
5680ee5cbfSDavid du Colombier 	cis.cisskip = attr ? 2 : 1;
5780ee5cbfSDavid du Colombier 	cis.cislen = m->len;
5880ee5cbfSDavid du Colombier 
5980ee5cbfSDavid du Colombier 	/* loop through all the tuples */
6080ee5cbfSDavid du Colombier 	for(i = 0; i < 1000; i++){
6180ee5cbfSDavid du Colombier 		this = cis.cispos;
6280ee5cbfSDavid du Colombier 		if(readc(&cis, &type) != 1)
6380ee5cbfSDavid du Colombier 			break;
6480ee5cbfSDavid du Colombier 		if(type == 0xFF)
6580ee5cbfSDavid du Colombier 			break;
6680ee5cbfSDavid du Colombier 		if(readc(&cis, &link) != 1)
6780ee5cbfSDavid du Colombier 			break;
6880ee5cbfSDavid du Colombier 		if(link == 0xFF)
6980ee5cbfSDavid du Colombier 			break;
7080ee5cbfSDavid du Colombier 
7180ee5cbfSDavid du Colombier 		n = link;
7280ee5cbfSDavid du Colombier 		if(link > 1 && subtuple != -1){
7380ee5cbfSDavid du Colombier 			if(readc(&cis, &c) != 1)
7480ee5cbfSDavid du Colombier 				break;
7580ee5cbfSDavid du Colombier 			subtype = c;
7680ee5cbfSDavid du Colombier 			n--;
7780ee5cbfSDavid du Colombier 		}else
7880ee5cbfSDavid du Colombier 			subtype = -1;
7980ee5cbfSDavid du Colombier 
8080ee5cbfSDavid du Colombier 		if(type == tuple && subtype == subtuple){
8180ee5cbfSDavid du Colombier 			p = v;
8280ee5cbfSDavid du Colombier 			for(l=0; l<nv && l<n; l++)
8380ee5cbfSDavid du Colombier 				if(readc(&cis, p++) != 1)
8480ee5cbfSDavid du Colombier 					break;
8580ee5cbfSDavid du Colombier 			pcmunmap(slotno, m);
8680ee5cbfSDavid du Colombier 			return nv;
8780ee5cbfSDavid du Colombier 		}
8880ee5cbfSDavid du Colombier 		cis.cispos = this + (2+link);
8980ee5cbfSDavid du Colombier 	}
9080ee5cbfSDavid du Colombier 	pcmunmap(slotno, m);
9180ee5cbfSDavid du Colombier 	return -1;
9280ee5cbfSDavid du Colombier }
9380ee5cbfSDavid du Colombier 
9480ee5cbfSDavid du Colombier int
pcmcistuple(int slotno,int tuple,int subtuple,void * v,int nv)9580ee5cbfSDavid du Colombier pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
9680ee5cbfSDavid du Colombier {
9780ee5cbfSDavid du Colombier 	int n;
9880ee5cbfSDavid du Colombier 
9980ee5cbfSDavid du Colombier 	/* try attribute space, then memory */
10080ee5cbfSDavid du Colombier 	if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
10180ee5cbfSDavid du Colombier 		return n;
10280ee5cbfSDavid du Colombier 	return xcistuple(slotno, tuple, subtuple, v, nv, 0);
10380ee5cbfSDavid du Colombier }
10480ee5cbfSDavid du Colombier 
10580ee5cbfSDavid du Colombier void
pcmcisread(PCMslot * pp)10680ee5cbfSDavid du Colombier pcmcisread(PCMslot *pp)
10780ee5cbfSDavid du Colombier {
1089a747e4fSDavid du Colombier 	int this;
10980ee5cbfSDavid du Colombier 	Cisdat cis;
1109a747e4fSDavid du Colombier 	PCMmap *m;
1119a747e4fSDavid du Colombier 	uchar type, link;
11280ee5cbfSDavid du Colombier 
11380ee5cbfSDavid du Colombier 	memset(pp->ctab, 0, sizeof(pp->ctab));
114*15174232SDavid du Colombier 	pp->ncfg = 0;
115*15174232SDavid du Colombier 	memset(pp->cfg, 0, sizeof(pp->cfg));
11680ee5cbfSDavid du Colombier 	pp->configed = 0;
11780ee5cbfSDavid du Colombier 	pp->nctab = 0;
11880ee5cbfSDavid du Colombier 	pp->verstr[0] = 0;
11980ee5cbfSDavid du Colombier 
1209a747e4fSDavid du Colombier 	/*
1219a747e4fSDavid du Colombier 	 * Read all tuples in attribute space.
1229a747e4fSDavid du Colombier 	 */
1239a747e4fSDavid du Colombier 	m = pcmmap(pp->slotno, 0, 0, 1);
1249a747e4fSDavid du Colombier 	if(m == 0)
1259a747e4fSDavid du Colombier 		return;
12680ee5cbfSDavid du Colombier 
1279a747e4fSDavid du Colombier 	cis.cisbase = KADDR(m->isa);
1289a747e4fSDavid du Colombier 	cis.cispos = 0;
1299a747e4fSDavid du Colombier 	cis.cisskip = 2;
1309a747e4fSDavid du Colombier 	cis.cislen = m->len;
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	/* loop through all the tuples */
1339a747e4fSDavid du Colombier 	for(;;){
1349a747e4fSDavid du Colombier 		this = cis.cispos;
1359a747e4fSDavid du Colombier 		if(readc(&cis, &type) != 1)
1369a747e4fSDavid du Colombier 			break;
1379a747e4fSDavid du Colombier 		if(type == 0xFF)
1389a747e4fSDavid du Colombier 			break;
1399a747e4fSDavid du Colombier 		if(readc(&cis, &link) != 1)
1409a747e4fSDavid du Colombier 			break;
1419a747e4fSDavid du Colombier 
1429a747e4fSDavid du Colombier 		switch(type){
1439a747e4fSDavid du Colombier 		default:
1449a747e4fSDavid du Colombier 			break;
145*15174232SDavid du Colombier 		case 6:
146*15174232SDavid du Colombier 			tlonglnkmfc(pp, &cis, type);
147*15174232SDavid du Colombier 			break;
1489a747e4fSDavid du Colombier 		case 0x15:
1499a747e4fSDavid du Colombier 			tvers1(pp, &cis, type);
1509a747e4fSDavid du Colombier 			break;
1519a747e4fSDavid du Colombier 		case 0x1A:
1529a747e4fSDavid du Colombier 			tcfig(pp, &cis, type);
1539a747e4fSDavid du Colombier 			break;
1549a747e4fSDavid du Colombier 		case 0x1B:
1559a747e4fSDavid du Colombier 			tentry(pp, &cis, type);
1569a747e4fSDavid du Colombier 			break;
15780ee5cbfSDavid du Colombier 		}
1589a747e4fSDavid du Colombier 
1599a747e4fSDavid du Colombier 		if(link == 0xFF)
1609a747e4fSDavid du Colombier 			break;
1619a747e4fSDavid du Colombier 		cis.cispos = this + (2+link);
16280ee5cbfSDavid du Colombier 	}
1639a747e4fSDavid du Colombier 	pcmunmap(pp->slotno, m);
16480ee5cbfSDavid du Colombier }
16580ee5cbfSDavid du Colombier 
16680ee5cbfSDavid du Colombier static ulong
getlong(Cisdat * cis,int size)16780ee5cbfSDavid du Colombier getlong(Cisdat *cis, int size)
16880ee5cbfSDavid du Colombier {
16980ee5cbfSDavid du Colombier 	uchar c;
17080ee5cbfSDavid du Colombier 	int i;
17180ee5cbfSDavid du Colombier 	ulong x;
17280ee5cbfSDavid du Colombier 
17380ee5cbfSDavid du Colombier 	x = 0;
17480ee5cbfSDavid du Colombier 	for(i = 0; i < size; i++){
17580ee5cbfSDavid du Colombier 		if(readc(cis, &c) != 1)
17680ee5cbfSDavid du Colombier 			break;
17780ee5cbfSDavid du Colombier 		x |= c<<(i*8);
17880ee5cbfSDavid du Colombier 	}
17980ee5cbfSDavid du Colombier 	return x;
18080ee5cbfSDavid du Colombier }
18180ee5cbfSDavid du Colombier 
18280ee5cbfSDavid du Colombier static void
tcfig(PCMslot * pp,Cisdat * cis,int)18380ee5cbfSDavid du Colombier tcfig(PCMslot *pp, Cisdat *cis, int )
18480ee5cbfSDavid du Colombier {
18580ee5cbfSDavid du Colombier 	uchar size, rasize, rmsize;
18680ee5cbfSDavid du Colombier 	uchar last;
18780ee5cbfSDavid du Colombier 
18880ee5cbfSDavid du Colombier 	if(readc(cis, &size) != 1)
18980ee5cbfSDavid du Colombier 		return;
19080ee5cbfSDavid du Colombier 	rasize = (size&0x3) + 1;
19180ee5cbfSDavid du Colombier 	rmsize = ((size>>2)&0xf) + 1;
19280ee5cbfSDavid du Colombier 	if(readc(cis, &last) != 1)
19380ee5cbfSDavid du Colombier 		return;
194*15174232SDavid du Colombier 
195*15174232SDavid du Colombier 	if(pp->ncfg >= 8){
196*15174232SDavid du Colombier 		print("tcfig: too many configuration registers\n");
197*15174232SDavid du Colombier 		return;
198*15174232SDavid du Colombier 	}
199*15174232SDavid du Colombier 
200*15174232SDavid du Colombier 	pp->cfg[pp->ncfg].caddr = getlong(cis, rasize);
201*15174232SDavid du Colombier 	pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize);
202*15174232SDavid du Colombier 	pp->ncfg++;
20380ee5cbfSDavid du Colombier }
20480ee5cbfSDavid du Colombier 
20580ee5cbfSDavid du Colombier static ulong vexp[8] =
20680ee5cbfSDavid du Colombier {
20780ee5cbfSDavid du Colombier 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
20880ee5cbfSDavid du Colombier };
20980ee5cbfSDavid du Colombier static ulong vmant[16] =
21080ee5cbfSDavid du Colombier {
21180ee5cbfSDavid du Colombier 	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
21280ee5cbfSDavid du Colombier };
21380ee5cbfSDavid du Colombier 
21480ee5cbfSDavid du Colombier static ulong
microvolt(Cisdat * cis)21580ee5cbfSDavid du Colombier microvolt(Cisdat *cis)
21680ee5cbfSDavid du Colombier {
21780ee5cbfSDavid du Colombier 	uchar c;
21880ee5cbfSDavid du Colombier 	ulong microvolts;
21980ee5cbfSDavid du Colombier 	ulong exp;
22080ee5cbfSDavid du Colombier 
22180ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
22280ee5cbfSDavid du Colombier 		return 0;
22380ee5cbfSDavid du Colombier 	exp = vexp[c&0x7];
22480ee5cbfSDavid du Colombier 	microvolts = vmant[(c>>3)&0xf]*exp;
22580ee5cbfSDavid du Colombier 	while(c & 0x80){
22680ee5cbfSDavid du Colombier 		if(readc(cis, &c) != 1)
22780ee5cbfSDavid du Colombier 			return 0;
22880ee5cbfSDavid du Colombier 		switch(c){
22980ee5cbfSDavid du Colombier 		case 0x7d:
23080ee5cbfSDavid du Colombier 			break;		/* high impedence when sleeping */
23180ee5cbfSDavid du Colombier 		case 0x7e:
23280ee5cbfSDavid du Colombier 		case 0x7f:
23380ee5cbfSDavid du Colombier 			microvolts = 0;	/* no connection */
23480ee5cbfSDavid du Colombier 			break;
23580ee5cbfSDavid du Colombier 		default:
23680ee5cbfSDavid du Colombier 			exp /= 10;
23780ee5cbfSDavid du Colombier 			microvolts += exp*(c&0x7f);
23880ee5cbfSDavid du Colombier 		}
23980ee5cbfSDavid du Colombier 	}
24080ee5cbfSDavid du Colombier 	return microvolts;
24180ee5cbfSDavid du Colombier }
24280ee5cbfSDavid du Colombier 
24380ee5cbfSDavid du Colombier static ulong
nanoamps(Cisdat * cis)24480ee5cbfSDavid du Colombier nanoamps(Cisdat *cis)
24580ee5cbfSDavid du Colombier {
24680ee5cbfSDavid du Colombier 	uchar c;
24780ee5cbfSDavid du Colombier 	ulong nanoamps;
24880ee5cbfSDavid du Colombier 
24980ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
25080ee5cbfSDavid du Colombier 		return 0;
25180ee5cbfSDavid du Colombier 	nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
25280ee5cbfSDavid du Colombier 	while(c & 0x80){
25380ee5cbfSDavid du Colombier 		if(readc(cis, &c) != 1)
25480ee5cbfSDavid du Colombier 			return 0;
25580ee5cbfSDavid du Colombier 		if(c == 0x7d || c == 0x7e || c == 0x7f)
25680ee5cbfSDavid du Colombier 			nanoamps = 0;
25780ee5cbfSDavid du Colombier 	}
25880ee5cbfSDavid du Colombier 	return nanoamps;
25980ee5cbfSDavid du Colombier }
26080ee5cbfSDavid du Colombier 
26180ee5cbfSDavid du Colombier /*
26280ee5cbfSDavid du Colombier  * only nominal voltage (feature 1) is important for config,
26380ee5cbfSDavid du Colombier  * other features must read card to stay in sync.
26480ee5cbfSDavid du Colombier  */
26580ee5cbfSDavid du Colombier static ulong
power(Cisdat * cis)26680ee5cbfSDavid du Colombier power(Cisdat *cis)
26780ee5cbfSDavid du Colombier {
26880ee5cbfSDavid du Colombier 	uchar feature;
26980ee5cbfSDavid du Colombier 	ulong mv;
27080ee5cbfSDavid du Colombier 
27180ee5cbfSDavid du Colombier 	mv = 0;
27280ee5cbfSDavid du Colombier 	if(readc(cis, &feature) != 1)
27380ee5cbfSDavid du Colombier 		return 0;
27480ee5cbfSDavid du Colombier 	if(feature & 1)
27580ee5cbfSDavid du Colombier 		mv = microvolt(cis);
27680ee5cbfSDavid du Colombier 	if(feature & 2)
27780ee5cbfSDavid du Colombier 		microvolt(cis);
27880ee5cbfSDavid du Colombier 	if(feature & 4)
27980ee5cbfSDavid du Colombier 		microvolt(cis);
28080ee5cbfSDavid du Colombier 	if(feature & 8)
28180ee5cbfSDavid du Colombier 		nanoamps(cis);
28280ee5cbfSDavid du Colombier 	if(feature & 0x10)
28380ee5cbfSDavid du Colombier 		nanoamps(cis);
28480ee5cbfSDavid du Colombier 	if(feature & 0x20)
28580ee5cbfSDavid du Colombier 		nanoamps(cis);
28680ee5cbfSDavid du Colombier 	if(feature & 0x40)
28780ee5cbfSDavid du Colombier 		nanoamps(cis);
28880ee5cbfSDavid du Colombier 	return mv/1000000;
28980ee5cbfSDavid du Colombier }
29080ee5cbfSDavid du Colombier 
29180ee5cbfSDavid du Colombier static ulong mantissa[16] =
29280ee5cbfSDavid du Colombier { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
29380ee5cbfSDavid du Colombier 
29480ee5cbfSDavid du Colombier static ulong exponent[8] =
29580ee5cbfSDavid du Colombier { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
29680ee5cbfSDavid du Colombier 
29780ee5cbfSDavid du Colombier static ulong
ttiming(Cisdat * cis,int scale)29880ee5cbfSDavid du Colombier ttiming(Cisdat *cis, int scale)
29980ee5cbfSDavid du Colombier {
30080ee5cbfSDavid du Colombier 	uchar unscaled;
30180ee5cbfSDavid du Colombier 	ulong nanosecs;
30280ee5cbfSDavid du Colombier 
30380ee5cbfSDavid du Colombier 	if(readc(cis, &unscaled) != 1)
30480ee5cbfSDavid du Colombier 		return 0;
30580ee5cbfSDavid du Colombier 	nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
30680ee5cbfSDavid du Colombier 	nanosecs = nanosecs * vexp[scale];
30780ee5cbfSDavid du Colombier 	return nanosecs;
30880ee5cbfSDavid du Colombier }
30980ee5cbfSDavid du Colombier 
31080ee5cbfSDavid du Colombier static void
timing(Cisdat * cis,PCMconftab * ct)31180ee5cbfSDavid du Colombier timing(Cisdat *cis, PCMconftab *ct)
31280ee5cbfSDavid du Colombier {
31380ee5cbfSDavid du Colombier 	uchar c, i;
31480ee5cbfSDavid du Colombier 
31580ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
31680ee5cbfSDavid du Colombier 		return;
31780ee5cbfSDavid du Colombier 	i = c&0x3;
31880ee5cbfSDavid du Colombier 	if(i != 3)
31980ee5cbfSDavid du Colombier 		ct->maxwait = ttiming(cis, i);		/* max wait */
32080ee5cbfSDavid du Colombier 	i = (c>>2)&0x7;
32180ee5cbfSDavid du Colombier 	if(i != 7)
32280ee5cbfSDavid du Colombier 		ct->readywait = ttiming(cis, i);		/* max ready/busy wait */
32380ee5cbfSDavid du Colombier 	i = (c>>5)&0x7;
32480ee5cbfSDavid du Colombier 	if(i != 7)
32580ee5cbfSDavid du Colombier 		ct->otherwait = ttiming(cis, i);		/* reserved wait */
32680ee5cbfSDavid du Colombier }
32780ee5cbfSDavid du Colombier 
32880ee5cbfSDavid du Colombier static void
iospaces(Cisdat * cis,PCMconftab * ct)32980ee5cbfSDavid du Colombier iospaces(Cisdat *cis, PCMconftab *ct)
33080ee5cbfSDavid du Colombier {
33180ee5cbfSDavid du Colombier 	uchar c;
33280ee5cbfSDavid du Colombier 	int i, nio;
33380ee5cbfSDavid du Colombier 
33480ee5cbfSDavid du Colombier 	ct->nio = 0;
33580ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
33680ee5cbfSDavid du Colombier 		return;
33780ee5cbfSDavid du Colombier 
33880ee5cbfSDavid du Colombier 	ct->bit16 = ((c>>5)&3) >= 2;
33980ee5cbfSDavid du Colombier 	if(!(c & 0x80)){
34080ee5cbfSDavid du Colombier 		ct->io[0].start = 0;
34180ee5cbfSDavid du Colombier 		ct->io[0].len = 1<<(c&0x1f);
34280ee5cbfSDavid du Colombier 		ct->nio = 1;
34380ee5cbfSDavid du Colombier 		return;
34480ee5cbfSDavid du Colombier 	}
34580ee5cbfSDavid du Colombier 
34680ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
34780ee5cbfSDavid du Colombier 		return;
34880ee5cbfSDavid du Colombier 
3499a747e4fSDavid du Colombier 	/*
3509a747e4fSDavid du Colombier 	 * For each of the range descriptions read the
3519a747e4fSDavid du Colombier 	 * start address and the length (value is length-1).
3529a747e4fSDavid du Colombier 	 */
35380ee5cbfSDavid du Colombier 	nio = (c&0xf)+1;
35480ee5cbfSDavid du Colombier 	for(i = 0; i < nio; i++){
35580ee5cbfSDavid du Colombier 		ct->io[i].start = getlong(cis, (c>>4)&0x3);
3569a747e4fSDavid du Colombier 		ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
35780ee5cbfSDavid du Colombier 	}
35880ee5cbfSDavid du Colombier 	ct->nio = nio;
35980ee5cbfSDavid du Colombier }
36080ee5cbfSDavid du Colombier 
36180ee5cbfSDavid du Colombier static void
irq(Cisdat * cis,PCMconftab * ct)36280ee5cbfSDavid du Colombier irq(Cisdat *cis, PCMconftab *ct)
36380ee5cbfSDavid du Colombier {
36480ee5cbfSDavid du Colombier 	uchar c;
36580ee5cbfSDavid du Colombier 
36680ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
36780ee5cbfSDavid du Colombier 		return;
36880ee5cbfSDavid du Colombier 	ct->irqtype = c & 0xe0;
36980ee5cbfSDavid du Colombier 	if(c & 0x10)
37080ee5cbfSDavid du Colombier 		ct->irqs = getlong(cis, 2);
37180ee5cbfSDavid du Colombier 	else
37280ee5cbfSDavid du Colombier 		ct->irqs = 1<<(c&0xf);
37380ee5cbfSDavid du Colombier 	ct->irqs &= 0xDEB8;		/* levels available to card */
37480ee5cbfSDavid du Colombier }
37580ee5cbfSDavid du Colombier 
37680ee5cbfSDavid du Colombier static void
memspace(Cisdat * cis,int asize,int lsize,int host)37780ee5cbfSDavid du Colombier memspace(Cisdat *cis, int asize, int lsize, int host)
37880ee5cbfSDavid du Colombier {
37980ee5cbfSDavid du Colombier 	ulong haddress, address, len;
38080ee5cbfSDavid du Colombier 
38180ee5cbfSDavid du Colombier 	len = getlong(cis, lsize)*256;
38280ee5cbfSDavid du Colombier 	address = getlong(cis, asize)*256;
38380ee5cbfSDavid du Colombier 	USED(len, address);
38480ee5cbfSDavid du Colombier 	if(host){
38580ee5cbfSDavid du Colombier 		haddress = getlong(cis, asize)*256;
38680ee5cbfSDavid du Colombier 		USED(haddress);
38780ee5cbfSDavid du Colombier 	}
38880ee5cbfSDavid du Colombier }
38980ee5cbfSDavid du Colombier 
39080ee5cbfSDavid du Colombier static void
tentry(PCMslot * pp,Cisdat * cis,int)39180ee5cbfSDavid du Colombier tentry(PCMslot *pp, Cisdat *cis, int )
39280ee5cbfSDavid du Colombier {
39380ee5cbfSDavid du Colombier 	uchar c, i, feature;
39480ee5cbfSDavid du Colombier 	PCMconftab *ct;
39580ee5cbfSDavid du Colombier 
39680ee5cbfSDavid du Colombier 	if(pp->nctab >= nelem(pp->ctab))
39780ee5cbfSDavid du Colombier 		return;
39880ee5cbfSDavid du Colombier 	if(readc(cis, &c) != 1)
39980ee5cbfSDavid du Colombier 		return;
40080ee5cbfSDavid du Colombier 	ct = &pp->ctab[pp->nctab++];
40180ee5cbfSDavid du Colombier 
40280ee5cbfSDavid du Colombier 	/* copy from last default config */
40380ee5cbfSDavid du Colombier 	if(pp->def)
40480ee5cbfSDavid du Colombier 		*ct = *pp->def;
40580ee5cbfSDavid du Colombier 
40680ee5cbfSDavid du Colombier 	ct->index = c & 0x3f;
40780ee5cbfSDavid du Colombier 
40880ee5cbfSDavid du Colombier 	/* is this the new default? */
40980ee5cbfSDavid du Colombier 	if(c & 0x40)
41080ee5cbfSDavid du Colombier 		pp->def = ct;
41180ee5cbfSDavid du Colombier 
41280ee5cbfSDavid du Colombier 	/* memory wait specified? */
41380ee5cbfSDavid du Colombier 	if(c & 0x80){
41480ee5cbfSDavid du Colombier 		if(readc(cis, &i) != 1)
41580ee5cbfSDavid du Colombier 			return;
41680ee5cbfSDavid du Colombier 		if(i&0x80)
41780ee5cbfSDavid du Colombier 			ct->memwait = 1;
41880ee5cbfSDavid du Colombier 	}
41980ee5cbfSDavid du Colombier 
42080ee5cbfSDavid du Colombier 	if(readc(cis, &feature) != 1)
42180ee5cbfSDavid du Colombier 		return;
42280ee5cbfSDavid du Colombier 	switch(feature&0x3){
42380ee5cbfSDavid du Colombier 	case 1:
42480ee5cbfSDavid du Colombier 		ct->vpp1 = ct->vpp2 = power(cis);
42580ee5cbfSDavid du Colombier 		break;
42680ee5cbfSDavid du Colombier 	case 2:
42780ee5cbfSDavid du Colombier 		power(cis);
42880ee5cbfSDavid du Colombier 		ct->vpp1 = ct->vpp2 = power(cis);
42980ee5cbfSDavid du Colombier 		break;
43080ee5cbfSDavid du Colombier 	case 3:
43180ee5cbfSDavid du Colombier 		power(cis);
43280ee5cbfSDavid du Colombier 		ct->vpp1 = power(cis);
43380ee5cbfSDavid du Colombier 		ct->vpp2 = power(cis);
43480ee5cbfSDavid du Colombier 		break;
43580ee5cbfSDavid du Colombier 	default:
43680ee5cbfSDavid du Colombier 		break;
43780ee5cbfSDavid du Colombier 	}
43880ee5cbfSDavid du Colombier 	if(feature&0x4)
43980ee5cbfSDavid du Colombier 		timing(cis, ct);
44080ee5cbfSDavid du Colombier 	if(feature&0x8)
44180ee5cbfSDavid du Colombier 		iospaces(cis, ct);
44280ee5cbfSDavid du Colombier 	if(feature&0x10)
44380ee5cbfSDavid du Colombier 		irq(cis, ct);
44480ee5cbfSDavid du Colombier 	switch((feature>>5)&0x3){
44580ee5cbfSDavid du Colombier 	case 1:
44680ee5cbfSDavid du Colombier 		memspace(cis, 0, 2, 0);
44780ee5cbfSDavid du Colombier 		break;
44880ee5cbfSDavid du Colombier 	case 2:
44980ee5cbfSDavid du Colombier 		memspace(cis, 2, 2, 0);
45080ee5cbfSDavid du Colombier 		break;
45180ee5cbfSDavid du Colombier 	case 3:
45280ee5cbfSDavid du Colombier 		if(readc(cis, &c) != 1)
45380ee5cbfSDavid du Colombier 			return;
45480ee5cbfSDavid du Colombier 		for(i = 0; i <= (c&0x7); i++)
45580ee5cbfSDavid du Colombier 			memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
45680ee5cbfSDavid du Colombier 		break;
45780ee5cbfSDavid du Colombier 	}
45880ee5cbfSDavid du Colombier 	pp->configed++;
45980ee5cbfSDavid du Colombier }
46080ee5cbfSDavid du Colombier 
46180ee5cbfSDavid du Colombier static void
tvers1(PCMslot * pp,Cisdat * cis,int)46280ee5cbfSDavid du Colombier tvers1(PCMslot *pp, Cisdat *cis, int )
46380ee5cbfSDavid du Colombier {
46480ee5cbfSDavid du Colombier 	uchar c, major, minor, last;
46580ee5cbfSDavid du Colombier 	int  i;
46680ee5cbfSDavid du Colombier 
46780ee5cbfSDavid du Colombier 	if(readc(cis, &major) != 1)
46880ee5cbfSDavid du Colombier 		return;
46980ee5cbfSDavid du Colombier 	if(readc(cis, &minor) != 1)
47080ee5cbfSDavid du Colombier 		return;
47180ee5cbfSDavid du Colombier 	last = 0;
47280ee5cbfSDavid du Colombier 	for(i = 0; i < sizeof(pp->verstr)-1; i++){
47380ee5cbfSDavid du Colombier 		if(readc(cis, &c) != 1)
47480ee5cbfSDavid du Colombier 			return;
47580ee5cbfSDavid du Colombier 		if(c == 0)
47680ee5cbfSDavid du Colombier 			c = ';';
47780ee5cbfSDavid du Colombier 		if(c == '\n')
47880ee5cbfSDavid du Colombier 			c = ';';
47980ee5cbfSDavid du Colombier 		if(c == 0xff)
48080ee5cbfSDavid du Colombier 			break;
48180ee5cbfSDavid du Colombier 		if(c == ';' && last == ';')
48280ee5cbfSDavid du Colombier 			continue;
48380ee5cbfSDavid du Colombier 		pp->verstr[i] = c;
48480ee5cbfSDavid du Colombier 		last = c;
48580ee5cbfSDavid du Colombier 	}
48680ee5cbfSDavid du Colombier 	pp->verstr[i] = 0;
48780ee5cbfSDavid du Colombier }
488*15174232SDavid du Colombier 
489*15174232SDavid du Colombier static void
tlonglnkmfc(PCMslot * pp,Cisdat * cis,int)490*15174232SDavid du Colombier tlonglnkmfc(PCMslot *pp, Cisdat *cis, int)
491*15174232SDavid du Colombier {
492*15174232SDavid du Colombier 	int i, npos, opos;
493*15174232SDavid du Colombier 	uchar nfn, space, expect, type, this, link;
494*15174232SDavid du Colombier 
495*15174232SDavid du Colombier 	readc(cis, &nfn);
496*15174232SDavid du Colombier 	for(i = 0; i < nfn; i++){
497*15174232SDavid du Colombier 		readc(cis, &space);
498*15174232SDavid du Colombier 		npos        = getlong(cis, 4);
499*15174232SDavid du Colombier 		opos        = cis->cispos;
500*15174232SDavid du Colombier 		cis->cispos = npos;
501*15174232SDavid du Colombier 		expect      = Linktarget;
502*15174232SDavid du Colombier 
503*15174232SDavid du Colombier 		while(1){
504*15174232SDavid du Colombier 			this = cis->cispos;
505*15174232SDavid du Colombier 			if(readc(cis, &type) != 1)
506*15174232SDavid du Colombier 				break;
507*15174232SDavid du Colombier 			if(type == 0xFF)
508*15174232SDavid du Colombier 				break;
509*15174232SDavid du Colombier 			if(readc(cis, &link) != 1)
510*15174232SDavid du Colombier 				break;
511*15174232SDavid du Colombier 
512*15174232SDavid du Colombier 			if(expect && expect != type){
513*15174232SDavid du Colombier 				print("tlonglnkmfc: expected %X found %X\n",
514*15174232SDavid du Colombier 					expect, type);
515*15174232SDavid du Colombier 				break;
516*15174232SDavid du Colombier 			}
517*15174232SDavid du Colombier 			expect = 0;
518*15174232SDavid du Colombier 
519*15174232SDavid du Colombier 			switch(type){
520*15174232SDavid du Colombier 			default:
521*15174232SDavid du Colombier 				break;
522*15174232SDavid du Colombier 			case 0x15:
523*15174232SDavid du Colombier 				tvers1(pp, cis, type);
524*15174232SDavid du Colombier 				break;
525*15174232SDavid du Colombier 			case 0x1A:
526*15174232SDavid du Colombier 				tcfig(pp, cis, type);
527*15174232SDavid du Colombier 				break;
528*15174232SDavid du Colombier 			case 0x1B:
529*15174232SDavid du Colombier 				tentry(pp, cis, type);
530*15174232SDavid du Colombier 				break;
531*15174232SDavid du Colombier 			}
532*15174232SDavid du Colombier 
533*15174232SDavid du Colombier 			if(link == 0xFF)
534*15174232SDavid du Colombier 				break;
535*15174232SDavid du Colombier 			cis->cispos = this + (2+link);
536*15174232SDavid du Colombier 		}
537*15174232SDavid du Colombier 		cis->cispos = opos;
538*15174232SDavid du Colombier 	}
539*15174232SDavid du Colombier }
540