/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:nvram.c 12.0$ */
/* $ACIS:nvram.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/nvram.c,v $ */

#ifndef lint
static char *rcsid = "$Header:nvram.c 12.0$";
#endif

#ifndef isxdigit
#include <ctype.h>
#endif
#include "err.h"

union crc {
	unsigned short word;
	char bytes[2];
	} crc;
struct nvram 
{
char	errlog[16];
char	usagelog[10];
char	iplsource[5];
char	configuration[10];
char	dialog_status[1];
char	shutdown_status[1];
char	time_data[2];
char	vrm_iodn[2];
char	reserved[1];
union	crc crc;
} nvram;

struct table {
char	*name;			/* name of the bytes */
char	*addr;			/* where to find it */
int	size;			/* how long it is */
} table [] = {
#define TABLE(name, extra) { "name", nvram.name extra, sizeof nvram.name },
TABLE(errlog,)
TABLE(usagelog,)
TABLE(iplsource,)
TABLE(configuration,)
TABLE(dialog_status,)
TABLE(shutdown_status,)
TABLE(time_data,)
TABLE(vrm_iodn,)
TABLE(reserved,)
TABLE(crc,.bytes)
};

#define NTABLE sizeof table/sizeof table[0]

int iflg;
int vflg;
int bflg;			/* if we've changed anything */
int zflg;
int cflg;			/* if crc explicitly updated */
#define NVRAM 0xf000880e	/* start of nvram */

main(argc,argv)
char **argv;
{
	
	register int i, j, k;
	register char *argp;
	union crc crc;

	for (i=1; i<argc; ++i)
		{
		argp = argv[i];
		if (*argp == '-')
			{
			switch(argp[1])
				{
			case 'i':
				++iflg;
				break;
			case 'v':
				++vflg;
				break;
			case 'z':
				++zflg;
				break;
			default:
				err("invalid switch %s",argp);
				}
			}
		else
			break;
		}
	if (argc <= 1)
		++vflg;
	if (!zflg)
		getnvram((char *) &nvram,NVRAM,sizeof nvram);

	crc.word = crc_gen((char *) &nvram, (sizeof nvram) - 2);

	if (vflg)
		{
		printf("nvram %x ... %x (%d bytes)\n",NVRAM, NVRAM + sizeof nvram - 1,
			sizeof nvram);
		for (j=0; j<NTABLE; ++j)
			prhex(table[j].name, table[j].addr, table[j].size);
		printf("calculated crc = %04x\n", crc.word); 
		}
	if (crc.word != nvram.crc.word && !iflg && !zflg)
		err("existing crc invalid (use -i to ignore crc or -z to zero nvram)");
#ifdef STANDALONE
	if (argc == 0 && yes("Change IPL order? [y/n] ", 0))
		{
		bzero(nvram.iplsource,sizeof nvram.iplsource);
		printf("\nEnter d0, d1, d2 for disk 0, 1, 2, or f0 or f1 for floppy 0 or 1,\n");
		printf("one entry per line, null entry when done.\n\n");
		for (j=0; j<sizeof nvram.iplsource;  ++j)
			{
			k = atox(prompt("device: ", 0));
			if (k == 0)
				break;
			nvram.iplsource[j] = k;
			}
		bflg++;
		}
	else
#endif
	while (i < argc)
		{
		char *name;
		char *addr;
		int length;
		for (j=0; j<NTABLE; ++j)
			{
			name = table[j].name;
			if (strncmp(argv[i], name, strlen(argv[i])) == 0)
				break;
			}
		if (j >= NTABLE)
			err("%s not in nvram",argv[i]);
		addr = table[j].addr;
		length = table[j].size;
		++i;
		bzero(addr,length);
		for (j=0; i<argc && j<length; ++i, ++j)
			{
			if (!ishex(argv[i]))
				break;
			k = atox(argv[i]);
			addr[j] = k;
			printf("%s[%d] = %02x\n",name,j,k);
			if (addr == nvram.crc.bytes)
				++cflg;		/* explicit crc update */
			++bflg;
			}
		}
	if (zflg || bflg)
		{
		if (!cflg)
			{
			crc.word = crc_gen((char *) &nvram, (sizeof nvram) - 2);
			nvram.crc.bytes[0] = crc.bytes[0];
			nvram.crc.bytes[1] = crc.bytes[1];
			}
		putnvram((char *) &nvram,NVRAM,sizeof nvram);
		printf("non-volitile ram updated\n");
		}
	exit(0);
}


getnvram(data,addr,size)
register char *data;
{

#ifdef STANDALONE
	copybytes((char *) addr, data, size);
#else
	register int fd;

	if ((fd = open("/dev/kmem1",0)) < 0)
		err("can't open /dev/kmem1");
	lseek(fd, addr, 0);
	if (read(fd, data, size) != size)
		err("read error");
	
	close(fd);
#endif
}

putnvram(data,addr,size)
register char *data;
{

#ifdef STANDALONE
	copybytes(data, (char *) addr, size);
#else
	register int fd;

	if ((fd = open("/dev/kmem1",1)) < 0)
		err("can't open /dev/kmem1");
	lseek(fd, addr, 0);
	if (write(fd, data, size) != size)
		err("write error");
	
	close(fd);
#endif
}

#ifndef STANDALONE
#include "err.c"
#endif

prhex(string,data,length)
register char *string;
register char *data;
register int length;
{
	printf("%-20s",string);
	while (--length >= 0)
		printf(" %02x",*data++);
	printf("\n");
}


#ifdef STANDALONE
copybytes(from,to, size)
register char *from, *to;
register int size;
{
	while (--size >= 0)
		*to++ = *from++;
}
#endif

ishex(string) 
register char *string;
{
	for (;*string; ++string)
		if (!isxdigit(*string))
			return(0);
	return(1);
}
