/*
*
* h3000 Option Pack Decode Utility
*
* Copyright 2000 Compaq Computer Corporation.
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Author: Charles Flynn.
*
* WARNING!!: The ioctl() interface will change in near future versions.
*/
                                                                

#include <stdio.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#if 0
#include "h3600_ts.h"           /* IOCTL definitions */
#else
#include <linux/h3600_ts.h>
#endif


/* The ioctl can be called from a ts, tsraw or key file descriptor */
#define DEV_NODE "/dev/h3600_ts"

#if 0
#define MAX_OPTION_PACK_FIELDS	24	/* see page 26 of spec */
#else
#define MAX_OPTION_PACK_FIELDS	17	/* see page 26 of spec */
#endif

#define TERMINATOR	0x0f0f0f0f	/* end of block marker */	
#define SIZEOF_TMPBUF	80		/* dont know what's best size here */

typedef struct {
	char name[32];
	unsigned int len;
} FIELD;

FIELD fields[MAX_OPTION_PACK_FIELDS] =
{
	{"Start of ID      ",1 },	/* 11 fields */
	{"Length of data   ",4},
	{"Version Indicator",1},
	{"Vendor ID        ",2},
	{"ID Number        ",2},
	{"Description      ",0},	/* zero means variable length */
	{"Type             ",1},
	{"Bootstrap Address",4},	/* kludge */
	{"OEM Info Address ",4},	/* kludge */
	{"Application Name ",4},	/* kludge */
	{"Terminator       ",4},

	{"Start of Control ",1},	/* 6 fields */
	{"Vendor ID        ",4},
	{"Driver ID        ",4},
	{"Memory Location  ",4},
	{"Stop Mem Location",4},
	{"Terminator       ",4},	/* 17 fields - 0x0f0f0f0f */

#if 0
	{"Vendor ID        ",4},	/* 7 fields */
	{"Driver ID        ",4},
	{"Driver name      ",0},
	{"Display name     ",0},
	{"Stream Prefix    ",3},
	{"Record Terminator",1},	/* 0x03 */
	{"Terminator       ",4}		/* ox0f0f0f0f */
#endif
};


main(int argc, char ** argv )
{
	SPI_READ ir;
	FIELD * pField;
	int fd;
	int err;
	unsigned next_offset=0;
	unsigned count = 0;
	unsigned long val;
	unsigned i;
	char tmpbuf[SIZEOF_TMPBUF];

	fd = open(DEV_NODE,O_RDWR);
	if( fd == -1 )
	{
		printf("\nUnable to open %s\n",DEV_NODE);
		exit(0);
	}

	for(i=0; i < MAX_OPTION_PACK_FIELDS; i++)
	{
	    pField = &fields[i];
	    ir.addr=next_offset;
	    ir.len=pField->len;
	    count=0;

	    if( ir.len )	/* fixed length read all bytes in one gulp */
	    {
		err = ioctl(fd,READ_SPI,(void *)&ir);
		if( !err )
		{
		    count=ir.len;
		    memcpy(tmpbuf,ir.buff,count);
		}
	    }
	    else /* variable length string - keep reading until null byte*/
	    {
		ir.len=1;
		do
		{
		    err = ioctl(fd,READ_SPI,(void *)&ir);
		    tmpbuf[count++]=ir.buff[0];
		    ir.addr = next_offset + count;
		} while( !err && ir.buff[0] && ( count < SIZEOF_TMPBUF) );

	    }

	    /* Enter here with known count and data in tmpbuf */

	    if(err)
	    {
		perror("A:bad ioctl\n");
                close(fd);
                exit(1);
	    }

	    /* TODO the following nested IFs need tidy up */
#if 0
	    printf("next_offset=%d count=%d\n",next_offset,count);
#endif
	    if( count )		/*for strings count includes the terminator*/
	    {
		if( count < SIZEOF_TMPBUF )
		{
		    if( pField->len )
		    {
			val=0;
			if( count > 4 )
				count=4;  /* TODO TODO remove when tested*/
			memcpy(&val,tmpbuf,count);
			next_offset += count;
			printf("[%02d:%02d]%s\t %08x\n",
				count,next_offset,pField->name,val);
		    }
		    else
		    {
			next_offset += count;
		        printf("[%02d:%02d]%s\t %s\n",
				count,next_offset,pField->name,tmpbuf);
		    }
		}
		else
		{
		    printf("ERROR: tmpbuf overflow\n");
		    break;
	        }
	    }
	    else
	    {
		printf("ERROR: nothing read\n");
		break;
	    }
	}

	close (fd);
}
