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