xref: /plan9/sys/src/cmd/aux/pcmcia.c (revision 1517423268547a2c0be806559a31cb95653443d5)
1 #include <u.h>
2 #include <libc.h>
3 
4 enum
5 {
6 	Linktarget = 0x13,
7 	Funcid = 0x21,
8 	End =	0xff,
9 };
10 
11 int fd;
12 int pos;
13 
14 void	tdevice(int, int);
15 void	tlonglnkmfc(int, int);
16 void	tfuncid(int, int);
17 void	tcfig(int, int);
18 void	tentry(int, int);
19 void	tvers1(int, int);
20 
21 void (*parse[256])(int, int) =
22 {
23 [1]		tdevice,
24 [6]		tlonglnkmfc,
25 [0x15]		tvers1,
26 [0x17]		tdevice,
27 [0x1A]		tcfig,
28 [0x1B]		tentry,
29 [Funcid]	tfuncid,
30 };
31 
32 int hex;
33 
34 void
fatal(char * fmt,...)35 fatal(char *fmt, ...)
36 {
37 	va_list arg;
38 	char buf[512];
39 
40 	va_start(arg, fmt);
41 	vseprint(buf, buf+sizeof(buf), fmt, arg);
42 	va_end(arg);
43 	fprint(2, "pcmcia: %s\n", buf);
44 	exits(buf);
45 }
46 
47 int
readc(void * x)48 readc(void *x)
49 {
50 	int rv;
51 
52 	seek(fd, 2*pos, 0);
53 	pos++;
54 	rv = read(fd, x, 1);
55 	if(hex)
56 		print("%2.2ux ", *(uchar*)x);
57 	return rv;
58 }
59 
60 int
tuple(int next,int expect)61 tuple(int next, int expect)
62 {
63 	uchar link;
64 	uchar type;
65 
66 	pos = next;
67 	if(readc(&type) != 1)
68 		return -1;
69 	if(type == 0xff)
70 		return -1;
71 print("type %.2uX\n", type & 0xff);
72 
73 	if(expect && expect != type){
74 		print("expected %.2uX found %.2uX\n",
75 			expect, type);
76 		return -1;
77 	}
78 
79 	if(readc(&link) != 1)
80 		return -1;
81 	if(parse[type])
82 		(*parse[type])(type, link);
83 	if(link == 0xff)
84 		next = -1;
85 	else
86 		next = next+2+link;
87 	return next;
88 }
89 
90 void
main(int argc,char * argv[])91 main(int argc, char *argv[])
92 {
93 	char *file;
94 	int next;
95 
96 	ARGBEGIN{
97 	case 'x':
98 		hex = 1;
99 	}ARGEND;
100 
101 	if(argc == 0)
102 		file = "#y/pcm0attr";
103 	else
104 		file = argv[0];
105 
106 	fd = open(file, OREAD);
107 	if(fd < 0)
108 		fatal("opening %s: %r", file);
109 
110 	for(next = 0; next >= 0;)
111 		next = tuple(next, 0);
112 }
113 
114 ulong speedtab[16] =
115 {
116 [1]	250,
117 [2]	200,
118 [3]	150,
119 [4]	100,
120 };
121 
122 ulong mantissa[16] =
123 {
124 [1]	10,
125 [2]	12,
126 [3]	13,
127 [4]	15,
128 [5]	20,
129 [6]	25,
130 [7]	30,
131 [8]	35,
132 [9]	40,
133 [0xa]	45,
134 [0xb]	50,
135 [0xc]	55,
136 [0xd]	60,
137 [0xe]	70,
138 [0xf]	80,
139 };
140 
141 ulong exponent[8] =
142 {
143 [0]	1,
144 [1]	10,
145 [2]	100,
146 [3]	1000,
147 [4]	10000,
148 [5]	100000,
149 [6]	1000000,
150 [7]	10000000,
151 };
152 
153 char *typetab[256] =
154 {
155 [1]	"Masked ROM",
156 [2]	"PROM",
157 [3]	"EPROM",
158 [4]	"EEPROM",
159 [5]	"FLASH",
160 [6]	"SRAM",
161 [7]	"DRAM",
162 [0xD]	"IO+MEM",
163 };
164 
165 ulong
getlong(int size)166 getlong(int size)
167 {
168 	uchar c;
169 	int i;
170 	ulong x;
171 
172 	x = 0;
173 	for(i = 0; i < size; i++){
174 		if(readc(&c) != 1)
175 			break;
176 		x |= c<<(i*8);
177 	}
178 	return x;
179 }
180 
181 void
tdevice(int ttype,int len)182 tdevice(int ttype, int len)
183 {
184 	uchar id;
185 	uchar type;
186 	uchar speed, aespeed;
187 	uchar size;
188 	ulong bytes, ns;
189 	char *tname, *ttname;
190 
191 	while(len > 0){
192 		if(readc(&id) != 1)
193 			return;
194 		len--;
195 		if(id == End)
196 			return;
197 
198 		/* PRISM cards have a device tuple with id = size = 0. */
199 		if(id == 0x00){
200 			if(readc(&size) != 1)
201 				return;
202 			len--;
203 			continue;
204 		}
205 
206 		speed = id & 0x7;
207 		if(speed == 0x7){
208 			if(readc(&speed) != 1)
209 				return;
210 			len--;
211 			if(speed & 0x80){
212 				if(readc(&aespeed) != 1)
213 					return;
214 				ns = 0;
215 			} else
216 				ns = (mantissa[(speed>>3)&0xf]*exponent[speed&7])/10;
217 		} else
218 			ns = speedtab[speed];
219 
220 		type = id>>4;
221 		if(type == 0xE){
222 			if(readc(&type) != 1)
223 				return;
224 			len--;
225 		}
226 		tname = typetab[type];
227 		if(tname == 0)
228 			tname = "unknown";
229 
230 		if(readc(&size) != 1)
231 			return;
232 		len--;
233 		bytes = ((size>>3)+1) * 512 * (1<<(2*(size&0x7)));
234 
235 		if(ttype == 1)
236 			ttname = "device";
237 		else
238 			ttname = "attr device";
239 		print("%s %ld bytes of %ldns %s\n", ttname, bytes, ns, tname);
240 	}
241 }
242 
243 void
tlonglnkmfc(int,int)244 tlonglnkmfc(int, int)
245 {
246 	int i, opos;
247 	uchar nfn, space, expect;
248 	int addr;
249 
250 	readc(&nfn);
251 	for(i = 0; i < nfn; i++){
252 		readc(&space);
253 		addr = getlong(4);
254 		opos = pos;
255 		expect = Linktarget;
256 		while(addr > 0){
257 			addr = tuple(addr, expect);
258 			expect = 0;
259 		}
260 		pos = opos;
261 	}
262 }
263 
264 static char *funcids[] = {
265 	"MULTI",
266 	"MEMORY",
267 	"SERIAL",
268 	"PARALLEL",
269 	"FIXED",
270 	"VIDEO",
271 	"NETWORK",
272 	"AIMS",
273 	"SCSI",
274 };
275 
276 void
tfuncid(int,int)277 tfuncid(int, int)
278 {
279 	uchar func;
280 
281 	readc(&func);
282 	print("Function %s\n",
283 		(func >= nelem(funcids))? "unknown function": funcids[func]);
284 }
285 
286 void
tvers1(int ttype,int len)287 tvers1(int ttype, int len)
288 {
289 	uchar c, major, minor;
290 	int  i;
291 	char string[512];
292 
293 	USED(ttype);
294 	if(readc(&major) != 1)
295 		return;
296 	len--;
297 	if(readc(&minor) != 1)
298 		return;
299 	len--;
300 	print("version %d.%d\n", major, minor);
301 	while(len > 0){
302 		for(i = 0; len > 0 && i < sizeof(string); i++){
303 			if(readc(&string[i]) != 1)
304 				return;
305 			len--;
306 			c = string[i];
307 			if(c == 0)
308 				break;
309 			if(c == 0xff){
310 				if(i != 0){
311 					string[i] = 0;
312 					print("\t%s<missing null>\n", string);
313 				}
314 				return;
315 			}
316 		}
317 		string[i] = 0;
318 		print("\t%s\n", string);
319 	}
320 }
321 
322 void
tcfig(int ttype,int len)323 tcfig(int ttype, int len)
324 {
325 	uchar size, rasize, rmsize;
326 	uchar last;
327 	ulong caddr;
328 	ulong cregs;
329 	int i;
330 
331 	USED(ttype, len);
332 	if(readc(&size) != 1)
333 		return;
334 	rasize = (size&0x3) + 1;
335 	rmsize = ((size>>2)&0xf) + 1;
336 	if(readc(&last) != 1)
337 		return;
338 	caddr = getlong(rasize);
339 	cregs = getlong(rmsize);
340 
341 	print("configuration registers at");
342 	for(i = 0; i < 16; i++)
343 		if((1<<i) & cregs)
344 			print(" (%d)0x%lux", i, caddr + i*2);
345 	print("\n");
346 }
347 
348 char *intrname[16] =
349 {
350 [0]	"memory",
351 [1]	"I/O",
352 [4]	"Custom 0",
353 [5]	"Custom 1",
354 [6]	"Custom 2",
355 [7]	"Custom 3",
356 };
357 
358 ulong vexp[8] =
359 {
360 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
361 };
362 ulong vmant[16] =
363 {
364 	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
365 };
366 
367 void
volt(char * name)368 volt(char *name)
369 {
370 	uchar c;
371 	ulong microv;
372 	ulong exp;
373 
374 	if(readc(&c) != 1)
375 		return;
376 	exp = vexp[c&0x7];
377 	microv = vmant[(c>>3)&0xf]*exp;
378 	while(c & 0x80){
379 		if(readc(&c) != 1)
380 			return;
381 		switch(c){
382 		case 0x7d:
383 			break;		/* high impedence when sleeping */
384 		case 0x7e:
385 		case 0x7f:
386 			microv = 0;	/* no connection */
387 			break;
388 		default:
389 			exp /= 10;
390 			microv += exp*(c&0x7f);
391 		}
392 	}
393 	print(" V%s %lduV", name, microv);
394 }
395 
396 void
amps(char * name)397 amps(char *name)
398 {
399 	uchar c;
400 	ulong amps;
401 
402 	if(readc(&c) != 1)
403 		return;
404 	amps = vexp[c&0x7]*vmant[(c>>3)&0xf];
405 	while(c & 0x80){
406 		if(readc(&c) != 1)
407 			return;
408 		if(c == 0x7d || c == 0x7e || c == 0x7f)
409 			amps = 0;
410 	}
411 	if(amps >= 1000000)
412 		print(" I%s %ldmA", name, amps/100000);
413 	else if(amps >= 1000)
414 		print(" I%s %lduA", name, amps/100);
415 	else
416 		print(" I%s %ldnA", name, amps*10);
417 }
418 
419 void
power(char * name)420 power(char *name)
421 {
422 	uchar feature;
423 
424 	print("\t%s: ", name);
425 	if(readc(&feature) != 1)
426 		return;
427 	if(feature & 1)
428 		volt("nominal");
429 	if(feature & 2)
430 		volt("min");
431 	if(feature & 4)
432 		volt("max");
433 	if(feature & 8)
434 		amps("static");
435 	if(feature & 0x10)
436 		amps("avg");
437 	if(feature & 0x20)
438 		amps("peak");
439 	if(feature & 0x40)
440 		amps("powerdown");
441 	print("\n");
442 }
443 
444 void
ttiming(char * name,int scale)445 ttiming(char *name, int scale)
446 {
447 	uchar unscaled;
448 	ulong scaled;
449 
450 	if(readc(&unscaled) != 1)
451 		return;
452 	scaled = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
453 	scaled = scaled * vexp[scale];
454 	print("\t%s %ldns\n", name, scaled);
455 }
456 
457 void
timing(void)458 timing(void)
459 {
460 	uchar c, i;
461 
462 	if(readc(&c) != 1)
463 		return;
464 	i = c&0x3;
465 	if(i != 3)
466 		ttiming("max wait", i);
467 	i = (c>>2)&0x7;
468 	if(i != 7)
469 		ttiming("max ready/busy wait", i);
470 	i = (c>>5)&0x7;
471 	if(i != 7)
472 		ttiming("reserved wait", i);
473 }
474 
475 void
range(int asize,int lsize)476 range(int asize, int lsize)
477 {
478 	ulong address, len;
479 
480 	address = getlong(asize);
481 	len = getlong(lsize);
482 	print("\t\t%lux - %lux\n", address, address+len);
483 }
484 
485 char *ioaccess[4] =
486 {
487 	" no access",
488 	" 8bit access only",
489 	" 8bit or 16bit access",
490 	" selectable 8bit or 8&16bit access",
491 };
492 
493 int
iospace(uchar c)494 iospace(uchar c)
495 {
496 	int i;
497 
498 	print("\tIO space %d address lines%s\n", c&0x1f, ioaccess[(c>>5)&3]);
499 	if((c & 0x80) == 0)
500 		return -1;
501 
502 	if(readc(&c) != 1)
503 		return -1;
504 
505 	for(i = (c&0xf)+1; i; i--)
506 		range((c>>4)&0x3, (c>>6)&0x3);
507 	return 0;
508 }
509 
510 void
iospaces(void)511 iospaces(void)
512 {
513 	uchar c;
514 
515 	if(readc(&c) != 1)
516 		return;
517 	iospace(c);
518 }
519 
520 void
irq(void)521 irq(void)
522 {
523 	uchar c;
524 	uchar irq1, irq2;
525 	ushort i, irqs;
526 
527 	if(readc(&c) != 1)
528 		return;
529 	if(c & 0x10){
530 		if(readc(&irq1) != 1)
531 			return;
532 		if(readc(&irq2) != 1)
533 			return;
534 		irqs = irq1|(irq2<<8);
535 	} else
536 		irqs = 1<<(c&0xf);
537 	print("\tinterrupts%s%s%s", (c&0x20)?":level":"", (c&0x40)?":pulse":"",
538 		(c&0x80)?":shared":"");
539 	for(i = 0; i < 16; i++)
540 		if(irqs & (1<<i))
541 			print(", %d", i);
542 	print("\n");
543 }
544 
545 void
memspace(int asize,int lsize,int host)546 memspace(int asize, int lsize, int host)
547 {
548 	ulong haddress, address, len;
549 
550 	len = getlong(lsize)*256;
551 	address = getlong(asize)*256;
552 	if(host){
553 		haddress = getlong(asize)*256;
554 		print("\tmemory address range 0x%lux - 0x%lux hostaddr 0x%lux\n",
555 			address, address+len, haddress);
556 	} else
557 		print("\tmemory address range 0x%lux - 0x%lux\n", address, address+len);
558 }
559 
560 void
misc(void)561 misc(void)
562 {
563 }
564 
565 void
tentry(int ttype,int len)566 tentry(int ttype, int len)
567 {
568 	uchar c, i, feature;
569 	char *tname;
570 	char buf[16];
571 
572 	USED(ttype, len);
573 	if(readc(&c) != 1)
574 		return;
575 	print("configuration %d%s\n", c&0x3f, (c&0x40)?" (default)":"");
576 	if(c & 0x80){
577 		if(readc(&i) != 1)
578 			return;
579 		tname = intrname[i & 0xf];
580 		if(tname == 0){
581 			tname = buf;
582 			sprint(buf, "type %d", i & 0xf);
583 		}
584 		print("\t%s device, %s%s%s%s\n", tname,
585 			(i&0x10)?" Battery status active":"",
586 			(i&0x20)?" Write Protect active":"",
587 			(i&0x40)?" Ready/Busy active":"",
588 			(i&0x80)?" Memory Wait required":"");
589 	}
590 	if(readc(&feature) != 1)
591 		return;
592 	switch(feature&0x3){
593 	case 1:
594 		power("Vcc");
595 		break;
596 	case 2:
597 		power("Vcc");
598 		power("Vpp");
599 		break;
600 	case 3:
601 		power("Vcc");
602 		power("Vpp1");
603 		power("Vpp2");
604 		break;
605 	}
606 	if(feature&0x4)
607 		timing();
608 	if(feature&0x8)
609 		iospaces();
610 	if(feature&0x10)
611 		irq();
612 	switch((feature>>5)&0x3){
613 	case 1:
614 		memspace(0, 2, 0);
615 		break;
616 	case 2:
617 		memspace(2, 2, 0);
618 		break;
619 	case 3:
620 		if(readc(&c) != 1)
621 			return;
622 		for(i = 0; i <= (c&0x7); i++)
623 			memspace((c>>5)&0x3, (c>>3)&0x3, c&0x80);
624 		break;
625 	}
626 	if(feature&0x80)
627 		misc();
628 }
629