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