1/*	$NetBSD: memswitch.c,v 1.10 2008/04/28 20:24:16 martin Exp $	*/
2
3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Minoura Makoto.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/* memswitch.c */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <err.h>
38#include <unistd.h>
39#include <fcntl.h>
40#include <errno.h>
41
42#include <sys/ioctl.h>
43
44#ifndef DEBUG
45#include <machine/sram.h>
46#else
47/*
48 * DEBUG -- works on other (faster) platforms;
49 *   store in a regular file instead of actual non-volatile static RAM.
50 */
51#define PATH_RAMFILE "/tmp/sramfile"
52#endif
53
54#include "memswitch.h"
55
56char *progname;
57int nflag = 0;
58u_int8_t *current_values = 0;
59u_int8_t *modified_values = 0;
60
61int main __P((int, char*[]));
62
63void
64usage(void)
65{
66	fprintf(stderr, "usage: %s -a\n", progname);
67	fprintf(stderr, "       %s [-h] variable ...\n", progname);
68	fprintf(stderr, "       %s -w variable=value ...\n", progname);
69	fprintf(stderr, "       %s [-rs] filename\n", progname);
70	exit(1);
71}
72
73int
74main(argc, argv)
75	int argc;
76	char *argv[];
77{
78	int ch;
79	enum md {
80		MD_NONE, MD_WRITE, MD_HELP, MD_SHOWALL, MD_SAVE, MD_RESTORE
81	} mode = MD_NONE;
82
83	progname = argv[0];
84
85	while ((ch = getopt(argc, argv, "whanrs")) != -1) {
86		switch (ch) {
87		case 'w':	/* write */
88			mode = MD_WRITE;
89			break;
90		case 'h':
91			mode = MD_HELP;
92			break;
93		case 'a':
94			mode = MD_SHOWALL;
95			break;
96		case 'n':
97			nflag = 1;
98			break;
99		case 's':
100			mode = MD_SAVE;
101			break;
102		case 'r':
103			mode = MD_RESTORE;
104			break;
105		}
106	}
107	argc -= optind;
108	argv += optind;
109
110	switch (mode) {
111	case MD_NONE:
112		if (argc == 0)
113			usage();
114		while (argv[0]) {
115			show_single(argv[0]);
116			argv++;
117		}
118		break;
119	case MD_SHOWALL:
120		if (argc)
121			usage();
122		show_all();
123		break;
124	case MD_WRITE:
125		if (argc == 0)
126			usage();
127		while (argv[0]) {
128			modify_single (argv[0]);
129			argv++;
130		}
131		flush();
132		break;
133	case MD_HELP:
134		if (argc == 0)
135			usage();
136		while (argv[0]) {
137			help_single(argv[0]);
138			argv++;
139		}
140		break;
141	case MD_SAVE:
142		if (argc != 1)
143			usage();
144		save(argv[0]);
145		break;
146	case MD_RESTORE:
147		if (argc != 1)
148			usage();
149		restore(argv[0]);
150		break;
151
152	}
153
154	return 0;
155}
156
157void
158show_single(name)
159	const char *name;
160{
161	int i;
162	int n = 0;
163	char fullname[50];
164	char valuestr[MAXVALUELEN];
165
166	for (i = 0; i < number_of_props; i++) {
167		snprintf(fullname, sizeof(fullname), "%s.%s",
168			 properties[i].class, properties[i].node);
169		if (strcmp(name, fullname) == 0 || strcmp(name, properties[i].class) == 0) {
170			properties[i].print(&properties[i], valuestr);
171			if (!nflag)
172				printf("%s=%s\n", fullname, valuestr);
173			n++;
174		}
175	}
176	if (n == 0) {
177		errx(1, "No such %s: %s", strstr(name, ".")?"property":"class", name);
178	}
179
180	return;
181}
182
183void
184show_all(void)
185{
186	int i;
187	char valuestr[MAXVALUELEN];
188
189	for (i = 0; i < number_of_props; i++) {
190		properties[i].print(&properties[i], valuestr);
191		if (!nflag)
192			printf("%s.%s=",
193			       properties[i].class, properties[i].node);
194		printf("%s\n", valuestr);
195	}
196
197	return;
198}
199
200void
201modify_single(expr)
202	const char *expr;
203{
204	int i, l, n;
205	char *class = NULL, *node = NULL;
206	const char *value;
207	char valuestr[MAXVALUELEN];
208
209	l = 0;
210	n = strlen(expr);
211	for (i = 0; i < n; i++) {
212		if (expr[i] == '.') {
213			l = i + 1;
214			class = alloca(l);
215			if (class == 0)
216				err(1, "alloca");
217			strncpy(class, expr, i);
218			class[i] = 0;
219			break;
220		}
221	}
222	if (i >= n)
223		errx(1, "Invalid expression: %s", expr);
224
225	for ( ; i < n; i++) {
226		if (expr[i] == '=') {
227			node = alloca(i - l + 1);
228			if (node == 0)
229				err(1, "alloca");
230			strncpy(node, &(expr[l]), i - l);
231			node[i - l] = 0;
232			break;
233		}
234	}
235	if (i >= n)
236		errx(1, "Invalid expression: %s", expr);
237
238	value = &(expr[++i]);
239
240	for (i = 0; i < number_of_props; i++) {
241		if (strcmp(properties[i].class, class) == 0 &&
242		    strcmp(properties[i].node, node) == 0) {
243			if (properties[i].parse(&properties[i], value) < 0) {
244				/* error: do nothing */
245			} else {
246				properties[i].print(&properties[i], valuestr);
247				printf("%s.%s -> %s\n", class, node, valuestr);
248			}
249			break;
250		}
251	}
252	if (i >= number_of_props) {
253		errx(1, "No such property: %s.%s", class, node);
254	}
255
256	return;
257}
258
259void
260help_single(name)
261	const char *name;
262{
263	int i;
264	char fullname[50];
265	char valuestr[MAXVALUELEN];
266
267	for (i = 0; i < number_of_props; i++) {
268		snprintf(fullname, sizeof(fullname), "%s.%s",
269		    properties[i].class, properties[i].node);
270		if (strcmp(name, fullname) == 0) {
271			properties[i].print(&properties[i], valuestr);
272			if (!nflag)
273				printf("%s=", fullname);
274			printf("%s\n", valuestr);
275			printf("%s", properties[i].descr);
276			break;
277		}
278	}
279	if (i >= number_of_props) {
280		errx(1, "No such property: %s", name);
281	}
282
283	return;
284}
285
286void
287alloc_modified_values(void)
288{
289	if (current_values == 0)
290		alloc_current_values();
291	modified_values = malloc(256);
292	if (modified_values == 0)
293		err(1, "malloc");
294	memcpy(modified_values, current_values, 256);
295}
296
297void
298alloc_current_values(void)
299{
300#ifndef DEBUG
301	int i;
302	int sramfd = 0;
303	struct sram_io buffer;
304
305	current_values = malloc(256);
306	if (current_values == 0)
307		err(1, "malloc");
308
309	sramfd = open(_PATH_DEVSRAM, O_RDONLY);
310	if (sramfd < 0)
311		err(1, "Opening %s", _PATH_DEVSRAM);
312
313	/* Assume SRAM_IO_SIZE = n * 16. */
314	for (i = 0; i < 256; i += SRAM_IO_SIZE) {
315		buffer.offset = i;
316		if (ioctl(sramfd, SIOGSRAM, &buffer) < 0)
317			err(1, "ioctl");
318		memcpy(&current_values[i], buffer.sram, SRAM_IO_SIZE);
319	}
320
321	close(sramfd);
322#else
323	int i;
324	int fd;
325	struct stat st;
326
327	current_values = malloc(256);
328	if (current_values == 0)
329		err(1, "malloc");
330
331	fd = open(PATH_RAMFILE, O_RDONLY);
332	if (fd < 0 && errno == ENOENT) {
333		modified_values = malloc(256);
334		if (modified_values == 0)
335			err(1, NULL);
336		for (i = 0; i < number_of_props; i++) {
337			properties[i].modified_value
338			    = properties[i].default_value;
339			properties[i].modified = 1;
340			properties[i].flush(&properties[i]);
341		}
342
343		fd = creat(PATH_RAMFILE, 0666);
344		if (fd < 0)
345			err(1, "Creating %s", PATH_RAMFILE);
346		if (write(fd, modified_values, 256) != 256)
347			err(1, "Writing %s", PATH_RAMFILE);
348		close(fd);
349		free(modified_values);
350		modified_values = 0;
351
352		fd = open(PATH_RAMFILE, O_RDONLY);
353	}
354	if (fd < 0)
355		err(1, "Opening %s", PATH_RAMFILE);
356	if (fstat(fd, &st) < 0)
357		err(1, "fstat");
358	if (st.st_size != 256)
359		errx(1, "PANIC! INVALID RAMFILE");
360	if (read(fd, current_values, 256) != 256)
361		err(1, "reading %s", PATH_RAMFILE);
362	close(fd);
363#endif
364
365	properties[PROP_MAGIC1].fill(&properties[PROP_MAGIC1]);
366	properties[PROP_MAGIC2].fill(&properties[PROP_MAGIC2]);
367	if ((properties[PROP_MAGIC1].current_value.longword != MAGIC1) ||
368	    (properties[PROP_MAGIC2].current_value.longword != MAGIC2))
369		errx(1, "PANIC! INVALID MAGIC");
370}
371
372void
373flush(void)
374{
375	int i;
376	int sramfd = 0;
377#ifndef DEBUG
378	struct sram_io buffer;
379#endif
380
381	for (i = 0; i < number_of_props; i++) {
382		if (properties[i].modified)
383			properties[i].flush(&properties[i]);
384	}
385
386	if (modified_values == 0)
387		/* Not modified at all. */
388		return;
389
390#ifndef DEBUG
391	/* Assume SRAM_IO_SIZE = n * 16. */
392	for (i = 0; i < 256; i += SRAM_IO_SIZE) {
393		if (memcmp(&current_values[i], &modified_values[i],
394			   SRAM_IO_SIZE) == 0)
395			continue;
396
397		if (sramfd == 0) {
398			sramfd = open(_PATH_DEVSRAM, O_RDWR);
399			if (sramfd < 0)
400				err(1, "Opening %s", _PATH_DEVSRAM);
401		}
402		buffer.offset = i;
403		memcpy(buffer.sram, &modified_values[i], SRAM_IO_SIZE);
404		if (ioctl(sramfd, SIOPSRAM, &buffer) < 0)
405			err(1, "ioctl");
406	}
407#else
408	sramfd = open(PATH_RAMFILE, O_WRONLY);
409	if (sramfd < 0)
410		err(1, "Opening %s", PATH_RAMFILE);
411	if (write(sramfd, modified_values, 256) != 256)
412		err(1, "Writing %s", PATH_RAMFILE);
413#endif
414
415	if (sramfd != 0)
416		close(sramfd);
417
418	return;
419}
420
421int
422save(name)
423	const char *name;
424{
425#ifndef DEBUG
426	int fd;
427
428	alloc_current_values();
429
430	if (strcmp(name, "-") == 0)
431		fd = 1;		/* standard output */
432	else {
433		fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
434		if (fd < 0)
435			err(1, "Opening output file");
436	}
437
438	if (write(fd, current_values, 256) != 256)
439		err(1, "Writing output file");
440
441	if (fd != 1)
442		close(fd);
443#else
444	fprintf(stderr, "Skipping save...\n");
445#endif
446
447	return 0;
448}
449
450int
451restore(name)
452	const char *name;
453{
454#ifndef DEBUG
455	int sramfd, fd, i;
456	struct sram_io buffer;
457
458	modified_values = malloc(256);
459	if (modified_values == 0)
460		err(1, "Opening %s", _PATH_DEVSRAM);
461
462	if (strcmp(name, "-") == 0)
463		fd = 0;		/* standard input */
464	else {
465		fd = open(name, O_RDONLY);
466		if (fd < 0)
467			err(1, "Opening input file");
468	}
469
470	if (read(fd, modified_values, 256) != 256)
471		err(1, "Reading input file");
472
473	if (fd != 0)
474		close(fd);
475
476	sramfd = open(_PATH_DEVSRAM, O_RDWR);
477	if (sramfd < 0)
478		err(1, "Opening %s", _PATH_DEVSRAM);
479
480	/* Assume SRAM_IO_SIZE = n * 16. */
481	for (i = 0; i < 256; i += SRAM_IO_SIZE) {
482		buffer.offset = i;
483		memcpy(buffer.sram, &modified_values[i], SRAM_IO_SIZE);
484		if (ioctl(sramfd, SIOPSRAM, &buffer) < 0)
485			err(1, "ioctl");
486	}
487
488	close(sramfd);
489#else
490	fprintf(stderr, "Skipping restore...\n");
491#endif
492
493	return 0;
494}
495