1/*	$NetBSD: methods.c,v 1.6 2008/04/28 20:24:17 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#include <stdio.h>
33#include <string.h>
34#include <err.h>
35#include <sys/types.h>
36
37#include "memswitch.h"
38#include "methods.h"
39
40int
41atoi_(p)
42	 const char **p;
43{
44	const char *p1 = *p;
45	int v = 0;
46	int first = 1;
47
48	while (*p1 == ' ' || *p1 == '\t')
49		p1++;
50
51	if (*p1 == 0) {
52		*p = 0;
53		return 0;
54	}
55	if (strlen(p1) >= 2 && strncasecmp("0x", p1, 2) == 0) {
56		p1 += 2;
57		while (1) {
58			if (*p1 >= '0' && *p1 <= '9') {
59				v *= 16;
60				v += *p1 - '0';
61				first = 0;
62			} else if (*p1 >= 'A' && *p1 <= 'F') {
63				v *= 16;
64				v += *p1 - 'A' + 10;
65				first = 0;
66			} else if (*p1 >= 'a' && *p1 <= 'f') {
67				v *= 16;
68				v += *p1 - 'a' + 10;
69				first = 0;
70			} else {
71				break;
72			}
73			p1++;
74		}
75	} else {
76		while (1) {
77			if (*p1 >= '0' && *p1 <= '9') {
78				v *= 10;
79				v += *p1 - '0';
80				first = 0;
81			} else {
82				break;
83			}
84			p1++;
85		}
86	}
87
88	if (first) {
89		*p = 0;
90		return 0;
91	}
92
93	while (*p1 == ' ' || *p1 == '\t') p1++;
94	*p = p1;
95	return v;
96}
97
98int
99fill_uchar(prop)
100	struct property *prop;
101{
102	if (current_values == 0)
103		alloc_current_values();
104
105	prop->current_value.byte[0] = current_values[prop->offset];
106	prop->current_value.byte[1] = 0;
107	prop->current_value.byte[2] = 0;
108	prop->current_value.byte[3] = 0;
109	prop->value_valid = 1;
110
111	return 0;
112}
113
114int
115fill_ushort(prop)
116	struct property *prop;
117{
118	if (current_values == 0)
119		alloc_current_values();
120
121	prop->current_value.byte[0] = current_values[prop->offset];
122	prop->current_value.byte[1] = current_values[prop->offset+1];
123	prop->current_value.byte[2] = 0;
124	prop->current_value.byte[3] = 0;
125	prop->value_valid = 1;
126
127	return 0;
128}
129
130int
131fill_ulong(prop)
132	struct property *prop;
133{
134	if (current_values == 0)
135		alloc_current_values();
136
137	prop->current_value.byte[0] = current_values[prop->offset];
138	prop->current_value.byte[1] = current_values[prop->offset+1];
139	prop->current_value.byte[2] = current_values[prop->offset+2];
140	prop->current_value.byte[3] = current_values[prop->offset+3];
141	prop->value_valid = 1;
142
143	return 0;
144}
145
146int
147flush_uchar(prop)
148	struct property *prop;
149{
150	if (!prop->modified)
151		return 0;
152
153	if (modified_values == 0)
154		alloc_modified_values();
155
156	modified_values[prop->offset] = prop->modified_value.byte[0];
157
158	return 0;
159}
160
161int
162flush_ushort(prop)
163	struct property *prop;
164{
165	if (!prop->modified)
166		return 0;
167
168	if (modified_values == 0)
169		alloc_modified_values();
170
171	modified_values[prop->offset] = prop->modified_value.byte[0];
172	modified_values[prop->offset+1] = prop->modified_value.byte[1];
173
174	return 0;
175}
176
177int
178flush_ulong(prop)
179	struct property *prop;
180{
181	if (!prop->modified)
182		return 0;
183
184	if (modified_values == 0)
185		alloc_modified_values();
186
187	modified_values[prop->offset] = prop->modified_value.byte[0];
188	modified_values[prop->offset+1] = prop->modified_value.byte[1];
189	modified_values[prop->offset+2] = prop->modified_value.byte[2];
190	modified_values[prop->offset+3] = prop->modified_value.byte[3];
191
192	return 0;
193}
194
195int
196flush_dummy(prop)
197	struct property *prop;
198{
199	return 0;
200}
201
202int
203parse_dummy(prop, value)
204	struct property *prop;
205	const char *value;
206{
207	warnx("Cannot modify %s.%s", prop->class, prop->node);
208
209	return -1;
210}
211
212int
213parse_byte(prop, value)
214	struct property *prop;
215	const char *value;
216{
217	const char *p = value;
218	int v;
219
220	v = atoi_(&p);
221	if (p == 0) {
222		warnx("%s: Invalid value", value);
223		return -1;
224	}
225
226	if (strcasecmp("MB", p) == 0)
227		v *= 1024 * 1024;
228	else if (strcasecmp("KB", p) == 0)
229		v *= 1024;
230	else if (*p != 0 &&
231		 strcasecmp("B", p) != 0) {
232		warnx("%s: Invalid value", value);
233		return -1;
234	}
235
236	if (v < prop->min) {
237		warnx("%s: Too small", value);
238		return -1;
239	} else if (v > prop->max) {
240		warnx("%s: Too large", value);
241		return -1;
242	}
243
244	prop->modified = 1;
245	prop->modified_value.longword = v;
246
247	return 0;
248}
249
250int
251parse_uchar(prop, value)
252	struct property *prop;
253	const char *value;
254{
255	const char *p = value;
256	int v;
257
258	v = atoi_(&p);
259	if (p == 0) {
260		warnx("%s: Invalid value", value);
261		return -1;
262	}
263
264	if (v < prop->min) {
265		warnx("%s: Too small", value);
266		return -1;
267	} else if (v > prop->max) {
268		warnx("%s: Too large", value);
269		return -1;
270	}
271
272	prop->modified = 1;
273	prop->modified_value.byte[0] = v;
274
275	return 0;
276}
277
278int
279parse_ulong(prop, value)
280	struct property *prop;
281	const char *value;
282{
283	const char *p = value;
284	int v;
285
286	v = atoi_(&p);
287	if (p == 0) {
288		warnx("%s: Invalid value", value);
289		return -1;
290	}
291
292	if (v < prop->min) {
293		warnx("%s: Too small", value);
294		return -1;
295	} else if (v > prop->max) {
296		warnx("%s: Too large", value);
297		return -1;
298	}
299
300	prop->modified = 1;
301	prop->modified_value.longword = v;
302
303	return 0;
304}
305
306int
307parse_ushort(prop, value)
308	struct property *prop;
309	const char *value;
310{
311	const char *p = value;
312	int v;
313
314	v = atoi_(&p);
315	if (p == 0) {
316		warnx("%s: Invalid value", value);
317		return -1;
318	}
319
320	if (v < prop->min) {
321		warnx("%s: Too small", value);
322		return -1;
323	} else if (v > prop->max) {
324		warnx("%s: Too large", value);
325		return -1;
326	}
327
328	prop->modified = 1;
329	prop->modified_value.word[0] = v;
330
331	return 0;
332}
333
334int
335parse_time(prop, value)
336	struct property *prop;
337	const char *value;
338{
339	const char *p = value;
340	int v;
341
342	while (*p == ' ' || *p == '\t') p++;
343	if (*p == '-') {
344		p++;
345		v = -atoi_(&p);
346	} else
347		v = atoi_(&p);
348	if (p == 0) {
349		warnx("%s: Invalid value", value);
350		return -1;
351	}
352
353	if (strcasecmp("hours", p) == 0 || strcasecmp("hour", p) == 0)
354		v *= 60 * 60;
355	else if (strcasecmp("minutes", p) == 0 ||
356		 strcasecmp("minute", p) == 0)
357		v *= 60;
358	else if (*p != 0 &&
359		 strcasecmp("second", p) != 0 &&
360		 strcasecmp("seconds", p) != 0) {
361		warnx("%s: Invalid value", value);
362		return -1;
363	}
364
365	if (v < prop->min) {
366		warnx("%s: Too small", value);
367		return -1;
368	} else if (v > prop->max) {
369		warnx("%s: Too large", value);
370		return -1;
371	}
372
373	prop->modified = 1;
374	prop->modified_value.longword = v;
375
376	return 0;
377}
378
379int
380parse_bootdev(prop, value)
381	struct property *prop;
382	const char *value;
383{
384	const char *p = value;
385	int v;
386	char expr_scsi[32];
387
388	while (*p == ' ' || *p == '\t') p++;
389
390	if (strcasecmp("STD", p) == 0)
391		v = 0;
392	else if (strcasecmp("ROM", p) == 0)
393		v = 0xa000;
394	else if (strcasecmp("RAM", p) == 0)
395		v = 0xb000;
396	else if (strncasecmp("HD", p, 2) == 0) {
397		p += 2;
398		v = atoi_(&p);
399		if (p == 0 || v < 0 || v > 15) {
400			warnx("%s: Invalid value", value);
401			return -1;
402		}
403		v *= 0x0100;
404		v += 0x8000;
405	} else if (strncasecmp("FD", p, 2) == 0) {
406		p += 2;
407		v = atoi_(&p);
408		if (p == 0 || v < 0 || v > 3) {
409			warnx("%s: Invalid value", value);
410			return -1;
411		}
412		v *= 0x0100;
413		v += 0x9070;
414	} else if (strncasecmp("INSCSI", p, 6) == 0 ||
415		   strncasecmp("EXSCSI", p, 6) == 0) {
416		int isin = strncasecmp("EXSCSI", p, 6);
417
418		p += 6;
419		v = atoi_(&p);
420		if (p == 0 || v < 0 || v > 7) {
421			warnx("%s: Invalid value", value);
422			return -1;
423		}
424
425		/* change boot.romaddr */
426		sprintf(expr_scsi, "boot.romaddr=0x%06x",
427			(isin ? 0xfc0000 : 0xea0020) + v * 4);
428		modify_single(expr_scsi);
429
430		/* boot.device again */
431		v = 0xa000;
432	} else {
433		warnx("%s: Invalid value", value);
434		return -1;
435	}
436
437	prop->modified = 1;
438	prop->modified_value.word[0] = v;
439
440	return 0;
441}
442
443int
444parse_serial(prop, value)
445	struct property *prop;
446	const char *value;
447#define NEXTSPEC	while (*p == ' ' || *p == '\t') p++;		\
448			if (*p++ != ',') {				\
449				warnx("%s: Invalid value", value);	\
450				return -1;				\
451			}						\
452			while (*p == ' ' || *p == '\t') p++;
453{
454	const char *p = value;
455	const char *q;
456	int baud, bit, parity, stop, flow;
457	static const int bauds[] = {75, 150, 300, 600, 1200, 2400, 4800, 9600,
458	    17361, 0};
459	static const char parities[] = "noe";
460	int i;
461
462	while (*p == ' ' || *p == '\t') p++;
463
464	/* speed */
465	baud = atoi_(&p);
466	if (p == 0) {
467		warnx("%s: Invalid value", value);
468		return -1;
469	}
470	for (i = 0; bauds[i]; i++)
471		if (baud == bauds[i])
472			break;
473	if (bauds[i] == 0) {
474		warnx("%d: Invalid speed", baud);
475		return -1;
476	}
477	baud = i;
478
479	NEXTSPEC;
480
481	/* bit size */
482	if (*p < '5' || *p > '8') {
483		warnx("%c: Invalid bit size", *p);
484		return -1;
485	}
486	bit = *p++ - '5';
487
488	NEXTSPEC;
489
490	/* parity */
491	q = strchr(parities, *p++);
492	if (q == 0) {
493		warnx("%c: Invalid parity spec", *p);
494		return -1;
495	}
496	parity = q - parities;
497
498	NEXTSPEC;
499
500	/* stop bit */
501	if (strncmp(p, "1.5", 3) == 0) {
502		stop = 2;
503		p += 3;
504	} else if (strncmp(p, "2", 1) == 0) {
505		stop = 0;
506		p++;
507	} else if (strncmp(p, "1", 1) == 0) {
508		stop = 1;
509		p++;
510	} else {
511		warnx("%s: Invalid value", value);
512		return -1;
513	}
514
515	NEXTSPEC;
516
517	/* flow */
518	if (*p == '-')
519		flow = 0;
520	else if (*p == 's')
521		flow = 1;
522	else {
523		warnx("%s: Invalid value", value);
524		return -1;
525	}
526
527	p++;
528	while (*p == ' ' || *p == '\t') p++;
529	if (*p != 0) {
530		warnx("%s: Invalid value", value);
531		return -1;
532	}
533
534	prop->modified = 1;
535	prop->modified_value.word[0] = ((stop << 14) +
536					(parity << 12) +
537					(bit << 10) +
538					(flow << 9) +
539					baud);
540
541	return 0;
542}
543#undef NEXTSPEC
544
545int
546parse_srammode(prop, value)
547	struct property *prop;
548	const char *value;
549{
550	static const char *const sramstrs[] = {"unused", "SRAMDISK", "program"};
551	int i;
552
553	for (i = 0; i <= 2; i++) {
554		if (strcasecmp(value, sramstrs[i]) == 0)
555			break;
556	}
557	if (i > 2) {
558		warnx("%s: Invalid value", value);
559		return -1;
560	}
561
562	prop->modified = 1;
563	prop->modified_value.byte[0] = i;
564
565	return 0;
566}
567
568int
569print_uchar(prop, str)
570	struct property *prop;
571	char *str;
572{
573	if (prop->modified)
574		snprintf(str, MAXVALUELEN,
575			 "%d", prop->modified_value.byte[0]);
576	else {
577		if (!prop->value_valid)
578			prop->fill(prop);
579		snprintf(str, MAXVALUELEN, "%d",
580			 prop->current_value.byte[0]);
581	}
582
583	return 0;
584}
585
586int
587print_ucharh(prop, str)
588	struct property *prop;
589	char *str;
590{
591	if (prop->modified)
592		snprintf(str, MAXVALUELEN,
593			 "0x%4.4x", prop->modified_value.byte[0]);
594	else {
595		if (!prop->value_valid)
596			prop->fill(prop);
597		snprintf(str, MAXVALUELEN,
598			 "0x%4.4x", prop->current_value.byte[0]);
599	}
600
601	return 0;
602}
603
604int
605print_ushorth(prop, str)
606	struct property *prop;
607	char *str;
608{
609	if (prop->modified)
610		snprintf(str, MAXVALUELEN,
611			  "0x%4.4x", prop->modified_value.word[0]);
612	else {
613		if (!prop->value_valid)
614			prop->fill(prop);
615		snprintf(str, MAXVALUELEN,
616			 "0x%4.4x", prop->current_value.word[0]);
617	}
618
619	return 0;
620}
621
622int
623print_ulong(prop, str)
624	struct property *prop;
625	char *str;
626{
627	if (prop->modified)
628		snprintf(str, MAXVALUELEN,
629			 "%ld", prop->modified_value.longword);
630	else {
631		if (!prop->value_valid)
632			prop->fill(prop);
633		snprintf(str, MAXVALUELEN,
634			 "%ld", prop->current_value.longword);
635	}
636
637	return 0;
638}
639
640int
641print_ulongh(prop, str)
642	struct property *prop;
643	char *str;
644{
645	if (prop->modified)
646		snprintf(str, MAXVALUELEN,
647			 "0x%8.8lx", prop->modified_value.longword);
648	else {
649		if (!prop->value_valid)
650			prop->fill(prop);
651		snprintf(str, MAXVALUELEN,
652			 "0x%8.8lx", prop->current_value.longword);
653	}
654
655	return 0;
656}
657
658int
659print_magic(prop, str)
660	struct property *prop;
661	char *str;
662{
663	if (!prop->value_valid)
664		prop->fill(prop);
665	snprintf(str, MAXVALUELEN, "%c%c%c%c",
666		 prop->current_value.byte[0],
667		 prop->current_value.byte[1],
668		 prop->current_value.byte[2],
669		 prop->current_value.byte[3]);
670
671	return 0;
672}
673
674int
675print_timesec(prop, str)
676	struct property *prop;
677	char *str;
678{
679	if (prop->modified)
680		snprintf(str, MAXVALUELEN,
681			 "%ld second", prop->modified_value.longword);
682	else {
683		if (!prop->value_valid)
684			prop->fill(prop);
685		snprintf(str, MAXVALUELEN,
686			 "%ld second", prop->current_value.longword);
687	}
688
689	return 0;
690}
691
692int
693print_bootdev(prop, str)
694	struct property *prop;
695	char *str;
696{
697	unsigned int v;
698
699	if (prop->modified)
700		v = prop->modified_value.word[0];
701	else {
702		if (!prop->value_valid)
703			prop->fill(prop);
704		v = prop->current_value.word[0];
705	}
706
707	if (v == 0)
708		strcpy(str, "STD");
709	else if (v == 0xa000)
710		strcpy(str, "ROM");
711	else if (v == 0xb000)
712		strcpy(str, "RAM");
713	else if (v >= 0x8000 && v < 0x9000)
714		snprintf(str, MAXVALUELEN, "HD%d", (v & 0x0f00) >> 8);
715	else if (v >= 0x9000 && v < 0xa000)
716		snprintf(str, MAXVALUELEN, "FD%d", (v & 0x0f00) >> 8);
717	else
718		snprintf(str, MAXVALUELEN, "%8.8x", v);
719
720	return 0;
721}
722
723int
724print_serial(prop, str)
725	struct property *prop;
726	char *str;
727{
728	unsigned int v;
729	const char *baud, *stop;
730	char bit, parity, flow;
731	static const char *const bauds[] = {"75", "150", "300", "600", "1200",
732			       "2400", "4800", "9600", "17361"};
733	static const char bits[] = "5678";
734	static const char parities[] = "noen";
735	static const char *const stops[] = {"2", "1", "1.5", "2"};
736	static const char flows[] = "-s";
737
738	if (prop->modified)
739		v = prop->modified_value.word[0];
740	else {
741		if (!prop->value_valid)
742			prop->fill(prop);
743		v = prop->current_value.word[0];
744	}
745
746	baud = bauds[v & 0x000f];
747	bit = bits[(v & 0x0c00) >> 10];
748	parity = parities[(v & 0x3000) >> 12];
749	stop = stops[(v & 0xe000) >> 14];
750	flow = flows[(v & 0x0200) >> 9];
751	sprintf(str, "%s,%c,%c,%s,%c", baud, bit, parity, stop, flow);
752
753	return 0;
754}
755
756int
757print_srammode(prop, str)
758	struct property *prop;
759	char *str;
760{
761	int v;
762	static const char *const sramstrs[] = {"unused", "SRAMDISK", "program"};
763
764	if (prop->modified)
765		v = prop->modified_value.byte[0];
766	else {
767		if (!prop->value_valid)
768			prop->fill(prop);
769		v = prop->current_value.byte[0];
770	}
771
772	if (v < 0 || v > 2)
773		strcpy(str, "INVALID");
774	else
775		strcpy(str, sramstrs[v]);
776
777	return 0;
778}
779