readcis.c revision 10217
1/* set tab=4
2 *	Read/dump CIS tuples.
3 */
4#include <stdio.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/ioctl.h>
9
10#include <pccard/card.h>
11#include <pccard/cis.h>
12
13#include "readcis.h"
14
15static int read_attr(int fd, char *bp, int len);
16struct tuple_list *read_one_tuplelist(int, int, off_t);
17int	ck_linktarget(int, off_t, int);
18
19struct tuple_info tuple_info[] =
20{
21	"Null tuple",							0x00, 0,
22	"Common memory descriptor",				0x01, 255,
23	"Checksum",								0x10, 5,
24	"Long link to attribute memory",		0x11, 4,
25	"Long link to common memory",			0x12, 4,
26	"Link target",							0x13, 3,
27	"No link",								0x14, 0,
28	"Version 1 info",						0x15, 255,
29	"Alternate language string",			0x16, 255,
30	"Attribute memory descriptor",			0x17, 255,
31	"JEDEC descr for common memory",		0x18, 255,
32	"JEDEC descr for attribute memory",		0x19, 255,
33	"Configuration map",					0x1A, 255,
34	"Configuration entry",					0x1B, 255,
35	"Other conditions for common memory",	0x1C, 255,
36	"Other conditions for attribute memory", 0x1D, 255,
37	"Geometry info for common memory",		0x1E, 255,
38	"Geometry info for attribute memory",	0x1F, 255,
39	"Manufacturer ID",						0x20, 4,
40	"Functional ID",						0x21, 255,
41	"Functional EXT",						0x22, 255,
42	"Software interleave",					0x23, 2,
43	"Version 2 Info",						0x40, 255,
44	"Data format",							0x41, 255,
45	"Geometry",								0x42, 4,
46	"Byte order",							0x43, 2,
47	"Card init date",						0x44, 4,
48	"Battery replacement",					0x45, 4,
49	"Organisation",							0x46, 255,
50	"Terminator",							0xFF, 255,
51	0, 0, 0
52	};
53
54/*
55 *	After reading the tuples, decode the relevant ones.
56 */
57struct cis *
58readcis(int fd)
59{
60struct tuple_list *tl;
61struct tuple *tp;
62struct cis *cp;
63
64	cp = xmalloc(sizeof(*cp));
65	cp->tlist = read_tuples(fd);
66	if (cp->tlist == 0)
67		return(NULL);
68
69	for (tl = cp->tlist; tl; tl = tl->next)
70	  for (tp = tl->tuples; tp; tp = tp->next)
71		{
72#if 0
73		printf("tuple code = 0x%02x, data is\n", tp->code);
74		dump(tp->data, tp->length);
75#endif
76		switch(tp->code)
77			{
78		case CIS_MEM_COMMON:	/* 0x01 */
79			device_desc(tp->data, tp->length, &cp->common_mem);
80			break;
81		case CIS_INFO_V1:	/* 0x15 */
82			cis_info(cp, tp->data, tp->length);
83			break;
84		case CIS_MEM_ATTR:	/* 0x17 */
85			device_desc(tp->data, tp->length, &cp->attr_mem);
86			break;
87		case CIS_CONF_MAP:	/* 0x1A */
88			config_map(cp, tp->data, tp->length);
89			break;
90		case CIS_CONFIG:	/* 0x1B */
91			cis_config(cp, tp->data, tp->length);
92			break;
93			}
94		}
95	return(cp);
96}
97/*
98 *	free_cis - delete cis entry.
99 */
100void
101freecis(struct cis *cp)
102{
103struct cis_ioblk *io;
104struct cis_memblk *mem;
105struct cis_config *conf;
106struct tuple *tp;
107struct tuple_list *tl;
108
109	while (tl = cp->tlist)
110		{
111		cp->tlist = tl->next;
112		while (tp = tl->tuples)
113			{
114			tl->tuples = tp->next;
115			if (tp->data)
116				free(tp->data);
117			}
118		}
119
120	while (conf = cp->conf)
121		{
122		cp->conf = conf->next;
123		while (io = conf->io)
124			{
125			conf->io = io->next;
126			free(io);
127			}
128		while (mem = conf->mem)
129			{
130			conf->mem = mem->next;
131			free(mem);
132			}
133		free(conf);
134		}
135	free(cp);
136}
137/*
138 *	Fills in CIS version data.
139 */
140cis_info(struct cis *cp, unsigned char *p, int len)
141{
142	cp->maj_v = *p++;
143	cp->min_v = *p++;
144	strncpy(cp->manuf, p, MAXSTR-1);
145	while (*p++)
146		;
147	strncpy(cp->vers, p, MAXSTR-1);
148	while (*p++)
149		;
150	strncpy(cp->add_info1, p, MAXSTR-1);
151	while (*p++)
152		;
153	strncpy(cp->add_info2, p, MAXSTR-1);
154}
155/*
156 *	device_desc - decode device descriptor.
157 */
158device_desc(p, len, dp)
159unsigned char *p;
160int	len;
161struct dev_mem *dp;
162{
163	while (len > 0 && *p != 0xFF)
164		{
165		dp->valid = 1;
166		dp->type = (*p & 0xF0) >> 4;
167		dp->wps = !!(*p & 0x8);
168		dp->speed = *p & 7;
169		p++;
170		if (*p != 0xFF)
171			{
172			dp->addr = *p >> 3;
173			dp->units = *p & 7;
174			}
175		p++;
176		len -= 2;
177		}
178}
179/*
180 *	configuration map of card control register.
181 */
182config_map(cp, p, len)
183struct cis *cp;
184unsigned char *p;
185int	len;
186{
187unsigned char *p1;
188int	i;
189union {
190	unsigned long l;
191	unsigned char b[4];
192	}u;
193
194	p1 = p + 1;
195	cp->last_config = *p1++ & 0x3F;
196	u.l = 0;
197	for (i = 0 ; i <= (*p & 3); i++)
198		u.b[i] = *p1++;
199	cp->reg_addr = u.l;
200	cp->ccrs = *p1;
201}
202/*
203 *	CIS config entry - Decode and build configuration entry.
204 */
205cis_config(cp, p, len)
206struct cis *cp;
207unsigned char *p;
208int len;
209{
210int	blks, x;
211int	i, j;
212union {
213	unsigned long l;
214	unsigned char b[4];
215	}u;
216struct cis_config *conf, *last;
217struct cis_memblk *mem;
218unsigned char feat;
219
220	conf = xmalloc(sizeof(*conf));
221	if (last = cp->conf)
222		{
223		while (last->next)
224			last = last->next;
225		last->next = conf;
226		}
227	else
228		cp->conf = conf;
229	conf->id = *p & 0x3F;
230	if (*p & 0x40)
231		cp->def_config = conf;
232	if (*p++ & 0x80)
233		p++;
234	feat = *p++;
235	for (i = 0; i < CIS_FEAT_POWER(feat); i++)
236		{
237		unsigned char parms = *p++;
238
239		conf->pwr = 1;
240		for (j = 0; j < 8; j++)
241			if (parms & (1 << j))
242					while (*p++ & 0x80)
243						;
244		}
245	if (feat & CIS_FEAT_TIMING)
246		{
247		conf->timing = 1;
248		i = *p++;
249		if (CIS_WAIT_SCALE(i) != 3)
250			p++;
251		if (CIS_READY_SCALE(i) != 7)
252			p++;
253		if (CIS_RESERVED_SCALE(i) != 7)
254			p++;
255		}
256	if (feat & CIS_FEAT_I_O)
257		{
258		conf->iospace = 1;
259		if (CIS_IO_RANGE & *p)
260			conf->io_blks = CIS_IO_BLKS(p[1])+1;
261		conf->io_addr = CIS_IO_ADDR(*p);
262		conf->io_bus = (*p >> 5) & 3;
263		if (*p++ & CIS_IO_RANGE)
264			{
265			struct cis_ioblk *io, *last = 0;
266			i = CIS_IO_ADSZ(*p);
267			j = CIS_IO_BLKSZ(*p++);
268			for (x = 0; x < conf->io_blks; x++)
269				{
270				io = xmalloc(sizeof(*io));
271				if (last)
272					last->next = io;
273				else
274					conf->io = io;
275				last = io;
276				u.l = 0;
277				switch(i)
278					{
279				case 0:
280					break;
281				case 1:
282					u.b[0] = *p++;
283					break;
284				case 2:
285					u.b[0] = *p++;
286					u.b[1] = *p++;
287					break;
288				case 3:
289					u.b[0] = *p++;
290					u.b[1] = *p++;
291					u.b[2] = *p++;
292					u.b[3] = *p++;
293					break;
294					}
295				io->addr = u.l;
296				u.l = 0;
297				switch(j)
298					{
299				case 0:
300					break;
301				case 1:
302					u.b[0] = *p++;
303					u.l++;
304					break;
305				case 2:
306					u.b[0] = *p++;
307					u.b[1] = *p++;
308					u.l++;
309					break;
310				case 3:
311					u.b[0] = *p++;
312					u.b[1] = *p++;
313					u.b[2] = *p++;
314					u.b[3] = *p++;
315					u.l++;
316					break;
317					}
318				io->size = u.l;
319				}
320			}
321		}
322	if (feat & CIS_FEAT_IRQ)
323		{
324		conf->irq = 1;
325		conf->irqlevel = *p & 0xF;
326		conf->irq_flags = *p & 0xF0;
327		if (*p++ & CIS_IRQ_MASK)
328			{
329			conf->irq_mask = (p[1] << 8) | p[0];
330			p += 2;
331			}
332		}
333	switch(CIS_FEAT_MEMORY(feat))
334		{
335	case 0:
336		break;
337	case 1:
338		conf->memspace = 1;
339		conf->mem = xmalloc(sizeof(*conf->mem));
340		conf->mem->length = ((p[1] << 8) | p[0])<<8;
341		break;
342	case 2:
343		conf->memspace = 1;
344		conf->mem = xmalloc(sizeof(*conf->mem));
345		conf->mem->length = ((p[1] << 8) | p[0]) << 8;
346		conf->mem->address = ((p[3] << 8) | p[2]) << 8;
347		break;
348	case 3:
349		conf->memspace = 1;
350		x = *p++;
351		conf->memwins = CIS_MEM_WINS(x);
352		for (i = 0; i < conf->memwins; i++)
353			{
354			struct cis_memblk *last;
355
356			mem = xmalloc(sizeof(*mem));
357			if (i == 0)
358				conf->mem = mem;
359			else
360				last->next = mem;
361			last = mem;
362			u.l = 0;
363			for (j = 0 ; j < CIS_MEM_LENSZ(x); j++)
364				u.b[j] = *p++;
365			mem->length = u.l << 8;
366			u.l = 0;
367			for (j = 0 ; j < CIS_MEM_ADDRSZ(x); j++)
368				u.b[j] = *p++;
369			mem->address = u.l << 8;
370			if (x & CIS_MEM_HOST)
371				{
372				u.l = 0;
373				for (j = 0 ; j < CIS_MEM_ADDRSZ(x); j++)
374					u.b[j] = *p++;
375				mem->host_address = u.l << 8;
376				}
377			}
378		break;
379		}
380	if (feat & 0x80)
381		{
382		conf->misc_valid = 1;
383		conf->misc = *p++;
384		}
385}
386/*
387 *	Read the tuples from the card.
388 *	The processing of tuples is as follows:
389 *		- Read tuples at attribute memory, offset 0.
390 *		- If a CIS_END is the first tuple, look for
391 *		  a tuple list at common memory offset 0; this list
392 *		  must start with a LINKTARGET.
393 *		- If a long link tuple was encountered, execute the long
394 *		  link.
395 *		- If a no-link tuple was seen, terminate processing.
396 *		- If no no-link tuple exists, and no long link tuple
397 *		  exists while processing the primary tuple list,
398 *		  then look for a LINKTARGET tuple in common memory.
399 *		- If a long link tuple is found in any list, then process
400 *		  it. Only one link is allowed per list.
401 */
402static struct tuple_list *tlist;
403
404struct tuple_list *
405read_tuples(int fd)
406{
407struct tuple_list *tl = 0, *last_tl;
408struct tuple *tp;
409int flag;
410off_t	offs;
411
412	tlist = 0;
413	last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t)0);
414/*
415 *	Now start processing the links (if any).
416 */
417	do
418		{
419		flag = MDF_ATTR;
420		tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A);
421		if (tp == 0)
422			{
423			flag = 0;
424			tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C);
425			}
426		if (tp && tp->length == 4)
427			{
428			offs = tp->data[0] |
429				(tp->data[1] << 8) |
430				(tp->data[2] << 16) |
431				(tp->data[3] << 24);
432#ifdef	DEBUG
433			printf("Checking long link at %ld (%s memory)\n",
434				offs, flag ? "Attribute" : "Common");
435#endif
436			if (ck_linktarget(fd, offs, flag))
437				{
438/*
439 *	If a link was found, then read the tuple list from it.
440 */
441				tl = read_one_tuplelist(fd, flag, offs);
442				last_tl->next = tl;
443				last_tl = tl;
444				}
445			}
446		} while (tl);
447/*
448 *	If the primary list had no NOLINK tuple, and no LINKTARGET,
449 *	then try to read a tuple list at common memory (offset 0).
450 */
451	if (find_tuple_in_list(tlist, CIS_NOLINK)==0 && tlist->next == 0 &&
452	    ck_linktarget(fd, (off_t)0, 0))
453		{
454#ifdef	DEBUG
455		printf("Reading long link at %ld (%s memory)\n",
456			offs, flag ? "Attribute" : "Common");
457#endif
458		tlist->next = read_one_tuplelist(fd, 0, (off_t)0);
459		}
460	return(tlist);
461}
462/*
463 *	Read one tuple list from the card.
464 */
465struct tuple_list *
466read_one_tuplelist(int fd, int flags, off_t offs)
467{
468struct tuple *tp, *last_tp, *first = 0;
469struct tuple_list *tl;
470struct tuple_info *tinfo;
471int	i, total = 0;
472unsigned char code, length;
473
474/*
475 *	Check to see if this memory has already been scanned.
476 */
477	for (tl = tlist; tl; tl = tl->next)
478		if (tl->offs == offs && tl->flags == (flags & MDF_ATTR))
479			return(0);
480	tl = xmalloc(sizeof(*tl));
481	tl->offs = offs;
482	tl->flags = flags & MDF_ATTR;
483	ioctl(fd, PIOCRWFLAG, &flags);
484	lseek(fd, offs, SEEK_SET);
485	do	{
486		if (read_attr(fd, &code, 1) != 1)
487			{
488			perror("CIS code read");
489			break;
490			}
491		total++;
492		if (code == CIS_NULL)
493			continue;
494		tp = xmalloc(sizeof(*tp));
495		tp->code = code;
496		if (read_attr(fd, &length, 1) != 1)
497			{
498			perror("CIS len read");
499			break;
500			}
501		total++;
502		tp->length = length;
503#ifdef	DEBUG
504		fprintf(stderr, "Tuple code = 0x%x, len = %d\n",
505			code, length);
506#endif
507		if (length == 0xFF)
508			{
509			length = tp->length = 0;
510			code = CIS_END;
511			}
512		if (length != 0)
513			{
514			total += length;
515			tp->data = xmalloc(length);
516			if (read_attr(fd, tp->data, length) != length)
517				{
518				perror("CIS read");
519				break;
520				}
521			}
522/*
523 *	Check the tuple, and ignore it if it isn't in the table
524 *	or the length is illegal.
525 */
526		tinfo = get_tuple_info(code);
527		if (tinfo == 0 || (tinfo->length != 255 && tinfo->length != length))
528			{
529			printf("code %s ignored\n", tuple_name(code));
530			tp->code = CIS_NULL;
531			}
532		if (tl->tuples==0)
533			tl->tuples = tp;
534		else
535			last_tp->next = tp;
536		last_tp = tp;
537		} while (code != CIS_END && total < 1024);
538	return(tl);
539}
540/*
541 *	return true if the offset points to a LINKTARGET tuple.
542 */
543int
544ck_linktarget(int fd, off_t offs, int flag)
545{
546char	blk[5];
547
548	ioctl(fd, PIOCRWFLAG, &flag);
549	lseek(fd, offs, SEEK_SET);
550	if (read_attr(fd, blk, 5) != 5)
551		return(0);
552	if (blk[0] == 0x13 &&
553	    blk[1] == 0x3 &&
554	    blk[2] == 'C' &&
555	    blk[3] == 'I' &&
556	    blk[4] == 'S')
557		return(1);
558	return(0);
559}
560/*
561 *	find_tuple - find the indicated tuple in the CIS
562 */
563struct tuple *
564find_tuple(struct cis *sp, unsigned char code)
565{
566struct tuple_list *tl;
567struct tuple *tp;
568
569	for (tl = sp->tlist; tl; tl = tl->next)
570		if (tp = find_tuple_in_list(tl, code))
571			return(tp);
572	return(0);
573}
574/*
575 *	find_tuple_in_list - find a tuple within a
576 *	single tuple list.
577 */
578struct tuple *
579find_tuple_in_list(struct tuple_list *tl, unsigned char code)
580{
581struct tuple *tp;
582
583	for (tp = tl->tuples; tp; tp = tp->next)
584		if (tp->code == code)
585			break;
586	return(tp);
587}
588static int
589read_attr(int fd, char *bp, int len)
590{
591char	blk[1024], *p = blk;
592int i,l;
593
594	if (len > sizeof(blk)/2)
595		len = sizeof(blk)/2;
596	l = i = read(fd, blk, len*2);
597	if (i <= 0)
598		{
599		printf("Read return %d bytes (expected %d)\n", i, len*2);
600		return(i);
601		}
602	while (i > 0)
603		{
604		*bp++ = *p++;
605		p++;
606		i -= 2;
607		}
608	return(l/2);
609}
610/*
611 *	return table entry for code.
612 */
613struct tuple_info *
614get_tuple_info(unsigned char code)
615{
616struct tuple_info *tp;
617
618	for (tp = tuple_info; tp->name; tp++)
619		if (tp->code == code)
620			return(tp);
621	printf("Code %d not found\n", code);
622	return(0);
623}
624char *
625tuple_name(unsigned char code)
626{
627struct tuple_info *tp;
628
629	tp = get_tuple_info(code);
630	if (tp)
631		return(tp->name);
632	return("Unknown");
633}
634