NetBSD/usr.sbin/memswitch/memswitch.c

496 lines
10 KiB
C

/* $NetBSD: memswitch.c,v 1.8 2004/01/05 23:23:38 jmmv Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Minoura Makoto.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* memswitch.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#ifndef DEBUG
#include <machine/sram.h>
#else
/*
* DEBUG -- works on other (faster) platforms;
* store in a regular file instead of actual non-volatile static RAM.
*/
#define PATH_RAMFILE "/tmp/sramfile"
#endif
#include "memswitch.h"
char *progname;
int nflag = 0;
u_int8_t *current_values = 0;
u_int8_t *modified_values = 0;
int main __P((int, char*[]));
void
usage(void)
{
fprintf (stderr, "usage: %s -a\n", progname);
fprintf (stderr, " %s [-h] variable ...\n", progname);
fprintf (stderr, " %s -w variable=value ...\n", progname);
fprintf (stderr, " %s [-rs] filename\n", progname);
exit(1);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int ch;
enum md {
MD_NONE, MD_WRITE, MD_HELP, MD_SHOWALL, MD_SAVE, MD_RESTORE
} mode = MD_NONE;
progname = argv[0];
while ((ch = getopt(argc, argv, "whanrs")) != -1) {
switch (ch) {
case 'w': /* write */
mode = MD_WRITE;
break;
case 'h':
mode = MD_HELP;
break;
case 'a':
mode = MD_SHOWALL;
break;
case 'n':
nflag = 1;
break;
case 's':
mode = MD_SAVE;
break;
case 'r':
mode = MD_RESTORE;
break;
}
}
argc -= optind;
argv += optind;
switch (mode) {
case MD_NONE:
if (argc == 0)
usage();
while (argv[0]) {
show_single (argv[0]);
argv++;
}
break;
case MD_SHOWALL:
if (argc)
usage();
show_all();
break;
case MD_WRITE:
if (argc == 0)
usage();
while (argv[0]) {
modify_single (argv[0]);
argv++;
}
flush ();
break;
case MD_HELP:
if (argc == 0)
usage();
while (argv[0]) {
help_single (argv[0]);
argv++;
}
break;
case MD_SAVE:
if (argc != 1)
usage();
save(argv[0]);
break;
case MD_RESTORE:
if (argc != 1)
usage();
restore(argv[0]);
break;
}
return 0;
}
void
show_single(name)
const char *name;
{
int i;
int n = 0;
char fullname[50];
char valuestr[MAXVALUELEN];
for (i = 0; i < number_of_props; i++) {
snprintf(fullname, sizeof(fullname), "%s.%s",
properties[i].class, properties[i].node);
if (strcmp(name, fullname) == 0 || strcmp(name, properties[i].class) == 0) {
properties[i].print (&properties[i], valuestr);
if (!nflag)
printf ("%s=%s\n", fullname, valuestr);
n++;
}
}
if (n == 0) {
errx (1, "No such %s: %s", strstr(name, ".")?"property":"class", name);
}
return;
}
void
show_all(void)
{
int i;
char valuestr[MAXVALUELEN];
for (i = 0; i < number_of_props; i++) {
properties[i].print (&properties[i], valuestr);
if (!nflag)
printf ("%s.%s=",
properties[i].class, properties[i].node);
printf ("%s\n", valuestr);
}
return;
}
void
modify_single(expr)
const char *expr;
{
int i, l, n;
char *class, *node;
const char *value;
char valuestr[MAXVALUELEN];
l = 0;
n = strlen(expr);
for (i = 0; i < n; i++) {
if (expr[i] == '.') {
l = i + 1;
class = alloca(l);
if (class == 0)
err (1, "alloca");
strncpy (class, expr, i);
class[i] = 0;
break;
}
}
if (i >= n)
errx (1, "Invalid expression: %s", expr);
for ( ; i < n; i++) {
if (expr[i] == '=') {
node = alloca(i - l + 1);
if (node == 0)
err (1, "alloca");
strncpy (node, &(expr[l]), i - l);
node[i - l] = 0;
break;
}
}
if (i >= n)
errx (1, "Invalid expression: %s", expr);
value = &(expr[++i]);
for (i = 0; i < number_of_props; i++) {
if (strcmp(properties[i].class, class) == 0 &&
strcmp(properties[i].node, node) == 0) {
if (properties[i].parse(&properties[i], value) < 0) {
/* error: do nothing */
} else {
properties[i].print (&properties[i], valuestr);
printf("%s.%s -> %s\n", class, node, valuestr);
}
break;
}
}
if (i >= number_of_props) {
errx (1, "No such property: %s.%s", class, node);
}
return;
}
void
help_single(name)
const char *name;
{
int i;
char fullname[50];
char valuestr[MAXVALUELEN];
for (i = 0; i < number_of_props; i++) {
snprintf(fullname, sizeof(fullname), "%s.%s",
properties[i].class, properties[i].node);
if (strcmp(name, fullname) == 0) {
properties[i].print (&properties[i], valuestr);
if (!nflag)
printf ("%s=", fullname);
printf ("%s\n", valuestr);
printf ("%s", properties[i].descr);
break;
}
}
if (i >= number_of_props) {
errx (1, "No such property: %s", name);
}
return;
}
void
alloc_modified_values(void)
{
if (current_values == 0)
alloc_current_values();
modified_values = malloc (256);
if (modified_values == 0)
err (1, "malloc");
memcpy (modified_values, current_values, 256);
}
void
alloc_current_values(void)
{
#ifndef DEBUG
int i;
int sramfd = 0;
struct sram_io buffer;
current_values = malloc (256);
if (current_values == 0)
err (1, "malloc");
sramfd = open (_PATH_DEVSRAM, O_RDONLY);
if (sramfd < 0)
err (1, "Opening %s", _PATH_DEVSRAM);
/* Assume SRAM_IO_SIZE = n * 16. */
for (i = 0; i < 256; i += SRAM_IO_SIZE) {
buffer.offset = i;
if (ioctl (sramfd, SIOGSRAM, &buffer) < 0)
err (1, "ioctl");
memcpy (&current_values[i], buffer.sram, SRAM_IO_SIZE);
}
close (sramfd);
#else
int i;
int fd;
struct stat st;
current_values = malloc (256);
if (current_values == 0)
err (1, "malloc");
fd = open (PATH_RAMFILE, O_RDONLY);
if (fd < 0 && errno == ENOENT) {
modified_values = malloc (256);
if (modified_values == 0)
err (1, NULL);
for (i = 0; i < number_of_props; i++) {
properties[i].modified_value
= properties[i].default_value;
properties[i].modified = 1;
properties[i].flush (&properties[i]);
}
fd = creat (PATH_RAMFILE, 0666);
if (fd < 0)
err (1, "Creating %s", PATH_RAMFILE);
if (write (fd, modified_values, 256) != 256)
err (1, "Writing %s", PATH_RAMFILE);
close (fd);
free (modified_values);
modified_values = 0;
fd = open (PATH_RAMFILE, O_RDONLY);
}
if (fd < 0)
err (1, "Opening %s", PATH_RAMFILE);
if (fstat (fd, &st) < 0)
err (1, "fstat");
if (st.st_size != 256)
errx (1, "PANIC! INVALID RAMFILE");
if (read (fd, current_values, 256) != 256)
err (1, "reading %s", PATH_RAMFILE);
close (fd);
#endif
properties[PROP_MAGIC1].fill (&properties[PROP_MAGIC1]);
properties[PROP_MAGIC2].fill (&properties[PROP_MAGIC2]);
if ((properties[PROP_MAGIC1].current_value.longword != MAGIC1) ||
(properties[PROP_MAGIC2].current_value.longword != MAGIC2))
errx (1, "PANIC! INVALID MAGIC");
}
void
flush(void)
{
int i;
int sramfd = 0;
#ifndef DEBUG
struct sram_io buffer;
#endif
for (i = 0; i < number_of_props; i++) {
if (properties[i].modified)
properties[i].flush(&properties[i]);
}
if (modified_values == 0)
/* Not modified at all. */
return;
#ifndef DEBUG
/* Assume SRAM_IO_SIZE = n * 16. */
for (i = 0; i < 256; i += SRAM_IO_SIZE) {
if (memcmp (&current_values[i], &modified_values[i],
SRAM_IO_SIZE) == 0)
continue;
if (sramfd == 0) {
sramfd = open (_PATH_DEVSRAM, O_RDWR);
if (sramfd < 0)
err (1, "Opening %s", _PATH_DEVSRAM);
}
buffer.offset = i;
memcpy (buffer.sram, &modified_values[i], SRAM_IO_SIZE);
if (ioctl (sramfd, SIOPSRAM, &buffer) < 0)
err (1, "ioctl");
}
#else
sramfd = open (PATH_RAMFILE, O_WRONLY);
if (sramfd < 0)
err (1, "Opening %s", PATH_RAMFILE);
if (write (sramfd, modified_values, 256) != 256)
err (1, "Writing %s", PATH_RAMFILE);
#endif
if (sramfd != 0)
close (sramfd);
return;
}
int
save(name)
const char *name;
{
#ifndef DEBUG
int fd;
alloc_current_values ();
if (strcmp (name, "-") == 0)
fd = 1; /* standard output */
else {
fd = open (name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0)
err (1, "Opening output file");
}
if (write (fd, current_values, 256) != 256)
err (1, "Writing output file");
if (fd != 1)
close (fd);
#else
fprintf (stderr, "Skipping save...\n");
#endif
return 0;
}
int
restore (name)
const char *name;
{
#ifndef DEBUG
int sramfd, fd, i;
struct sram_io buffer;
modified_values = malloc (256);
if (modified_values == 0)
err (1, "Opening %s", _PATH_DEVSRAM);
if (strcmp (name, "-") == 0)
fd = 0; /* standard input */
else {
fd = open (name, O_RDONLY);
if (fd < 0)
err (1, "Opening input file");
}
sramfd = open (_PATH_DEVSRAM, O_RDONLY);
if (sramfd < 0)
err (1, "Opening %s", _PATH_DEVSRAM);
/* Assume SRAM_IO_SIZE = n * 16. */
for (i = 0; i < 256; i += SRAM_IO_SIZE) {
buffer.offset = i;
memcpy (buffer.sram, &modified_values[i], SRAM_IO_SIZE);
if (ioctl (sramfd, SIOPSRAM, &buffer) < 0)
err (1, "ioctl");
}
close (sramfd);
#else
fprintf (stderr, "Skipping restore...\n");
#endif
return 0;
}