No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / eeprom / eehandlers.c
blob36149d17e3a3027e33d3d1abef6838c695b7b2ad
1 /* $NetBSD: eehandlers.c,v 1.14 2008/04/28 20:24:15 martin Exp $ */
3 /*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
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.
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.
32 #include <sys/types.h>
33 #include <ctype.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <util.h>
44 #include <machine/eeprom.h>
45 #ifdef __sparc__
46 #include <machine/openpromio.h>
47 #endif /* __sparc__ */
49 #include "defs.h"
51 extern char *path_eeprom;
52 extern int eval;
53 extern int update_checksums;
54 extern int ignore_checksum;
55 extern int fix_checksum;
56 extern int cksumfail;
57 extern u_short writecount;
59 static char err_str[BUFSIZE];
61 static void badval (struct keytabent *, char *);
62 static int doio (struct keytabent *, u_char *, ssize_t, int);
64 struct keytabent eekeytab[] = {
65 { "hwupdate", 0x10, ee_hwupdate },
66 { "memsize", 0x14, ee_num8 },
67 { "memtest", 0x15, ee_num8 },
68 { "scrsize", 0x16, ee_screensize },
69 { "watchdog_reboot", 0x17, ee_truefalse },
70 { "default_boot", 0x18, ee_truefalse },
71 { "bootdev", 0x19, ee_bootdev },
72 { "kbdtype", 0x1e, ee_kbdtype },
73 { "console", 0x1f, ee_constype },
74 { "keyclick", 0x21, ee_truefalse },
75 { "diagdev", 0x22, ee_bootdev },
76 { "diagpath", 0x28, ee_diagpath },
77 { "columns", 0x50, ee_num8 },
78 { "rows", 0x51, ee_num8 },
79 { "ttya_use_baud", 0x58, ee_truefalse },
80 { "ttya_baud", 0x59, ee_num16 },
81 { "ttya_no_rtsdtr", 0x5b, ee_truefalse },
82 { "ttyb_use_baud", 0x60, ee_truefalse },
83 { "ttyb_baud", 0x61, ee_num16 },
84 { "ttyb_no_rtsdtr", 0x63, ee_truefalse },
85 { "banner", 0x68, ee_banner },
86 { "secure", 0, ee_notsupp },
87 { "bad_login", 0, ee_notsupp },
88 { "password", 0, ee_notsupp },
89 { NULL, 0, ee_notsupp },
92 #define BARF(kt) { \
93 badval((kt), arg); \
94 ++eval; \
95 return; \
98 #define FAILEDREAD(kt) { \
99 warnx("%s", err_str); \
100 warnx("failed to read field `%s'", (kt)->kt_keyword); \
101 ++eval; \
102 return; \
105 #define FAILEDWRITE(kt) { \
106 warnx("%s", err_str); \
107 warnx("failed to update field `%s'", (kt)->kt_keyword); \
108 ++eval; \
109 return; \
112 void
113 ee_action(keyword, arg)
114 char *keyword, *arg;
116 struct keytabent *ktent;
118 for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
119 if (strcmp(ktent->kt_keyword, keyword) == 0) {
120 (*ktent->kt_handler)(ktent, arg);
121 return;
125 warnx("unknown keyword %s", keyword);
126 ++eval;
129 void
130 ee_dump()
132 struct keytabent *ktent;
134 for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
135 (*ktent->kt_handler)(ktent, NULL);
138 void
139 ee_hwupdate(ktent, arg)
140 struct keytabent *ktent;
141 char *arg;
143 time_t t;
144 char *cp, *cp2;
146 if (arg) {
147 if ((strcmp(arg, "now") == 0) ||
148 (strcmp(arg, "today") == 0)) {
149 if ((t = time(NULL)) == (time_t)(-1)) {
150 warnx("can't get current time");
151 ++eval;
152 return;
154 } else
155 if ((t = parsedate(arg, NULL, NULL)) == (time_t)(-1))
156 BARF(ktent);
158 if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
159 FAILEDWRITE(ktent);
160 } else
161 if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
162 FAILEDREAD(ktent);
164 cp = ctime(&t);
165 if ((cp2 = strrchr(cp, '\n')) != NULL)
166 *cp2 = '\0';
168 printf("%s=%ld (%s)\n", ktent->kt_keyword, (long)t, cp);
171 void
172 ee_num8(ktent, arg)
173 struct keytabent *ktent;
174 char *arg;
176 u_char num8 = 0;
177 u_int num32;
178 int i;
180 if (arg) {
181 for (i = 0; i < (int)strlen(arg) - 1; ++i)
182 if (!isdigit((unsigned char)arg[i]))
183 BARF(ktent);
184 num32 = atoi(arg);
185 if (num32 > 0xff)
186 BARF(ktent);
187 num8 += num32;
188 if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
189 FAILEDWRITE(ktent);
190 } else
191 if (doio(ktent, &num8, sizeof(num8), IO_READ))
192 FAILEDREAD(ktent);
194 printf("%s=%d\n", ktent->kt_keyword, num8);
197 void
198 ee_num16(ktent, arg)
199 struct keytabent *ktent;
200 char *arg;
202 u_int16_t num16 = 0;
203 u_int num32;
204 int i;
206 if (arg) {
207 for (i = 0; i < (int)strlen(arg) - 1; ++i)
208 if (!isdigit((unsigned char)arg[i]))
209 BARF(ktent);
210 num32 = atoi(arg);
211 if (num32 > 0xffff)
212 BARF(ktent);
213 num16 += num32;
214 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
215 FAILEDWRITE(ktent);
216 } else
217 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
218 FAILEDREAD(ktent);
220 printf("%s=%d\n", ktent->kt_keyword, num16);
223 static struct strvaltabent scrsizetab[] = {
224 { "1152x900", EE_SCR_1152X900 },
225 { "1024x1024", EE_SCR_1024X1024 },
226 { "1600x1280", EE_SCR_1600X1280 },
227 { "1440x1440", EE_SCR_1440X1440 },
228 { NULL, 0 },
231 void
232 ee_screensize(ktent, arg)
233 struct keytabent *ktent;
234 char *arg;
236 struct strvaltabent *svp;
237 u_char scsize;
239 if (arg) {
240 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
241 if (strcmp(svp->sv_str, arg) == 0)
242 break;
243 if (svp->sv_str == NULL)
244 BARF(ktent);
246 scsize = svp->sv_val;
247 if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
248 FAILEDWRITE(ktent);
249 } else {
250 if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
251 FAILEDREAD(ktent);
253 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
254 if (svp->sv_val == scsize)
255 break;
256 if (svp->sv_str == NULL) {
257 warnx("unknown %s value %d", ktent->kt_keyword,
258 scsize);
259 return;
262 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
265 static struct strvaltabent truthtab[] = {
266 { "true", EE_TRUE },
267 { "false", EE_FALSE },
268 { NULL, 0 },
271 void
272 ee_truefalse(ktent, arg)
273 struct keytabent *ktent;
274 char *arg;
276 struct strvaltabent *svp;
277 u_char truth;
279 if (arg) {
280 for (svp = truthtab; svp->sv_str != NULL; ++svp)
281 if (strcmp(svp->sv_str, arg) == 0)
282 break;
283 if (svp->sv_str == NULL)
284 BARF(ktent);
286 truth = svp->sv_val;
287 if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
288 FAILEDWRITE(ktent);
289 } else {
290 if (doio(ktent, &truth, sizeof(truth), IO_READ))
291 FAILEDREAD(ktent);
293 for (svp = truthtab; svp->sv_str != NULL; ++svp)
294 if (svp->sv_val == truth)
295 break;
296 if (svp->sv_str == NULL) {
297 warnx("unknown truth value 0x%x for %s", truth,
298 ktent->kt_keyword);
299 return;
302 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
305 void
306 ee_bootdev(ktent, arg)
307 struct keytabent *ktent;
308 char *arg;
310 u_char dev[5];
311 int i;
312 size_t arglen;
313 char *cp;
315 if (arg) {
317 * The format of the string we accept is the following:
318 * cc(n,n,n)
319 * where:
320 * c -- an alphabetical character [a-z]
321 * n -- a number in hexadecimal, between 0 and ff,
322 * with no leading `0x'.
324 arglen = strlen(arg);
325 if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
326 arg[arglen - 1] != ')')
327 BARF(ktent);
329 /* Handle the first 2 letters. */
330 for (i = 0; i < 2; ++i) {
331 if (arg[i] < 'a' || arg[i] > 'z')
332 BARF(ktent);
333 dev[i] = (u_char)arg[i];
336 /* Handle the 3 `0x'-less hex values. */
337 cp = &arg[3];
338 for (i = 2; i < 5; ++i) {
339 if (*cp == '\0')
340 BARF(ktent);
342 if (*cp >= '0' && *cp <= '9')
343 dev[i] = *cp++ - '0';
344 else if (*cp >= 'a' && *cp <= 'f')
345 dev[i] = 10 + (*cp++ - 'a');
346 else
347 BARF(ktent);
349 /* Deal with a second digit. */
350 if (*cp >= '0' && *cp <= '9') {
351 dev[i] <<= 4;
352 dev[i] &= 0xf0;
353 dev[i] += *cp++ - '0';
354 } else if (*cp >= 'a' && *cp <= 'f') {
355 dev[i] <<= 4;
356 dev[i] &= 0xf0;
357 dev[i] += 10 + (*cp++ - 'a');
360 /* Ensure we have the correct delimiter. */
361 if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
362 ++cp;
363 continue;
364 } else
365 BARF(ktent);
367 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
368 FAILEDWRITE(ktent);
369 } else
370 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
371 FAILEDREAD(ktent);
373 printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
374 dev[1], dev[2], dev[3], dev[4]);
377 void
378 ee_kbdtype(ktent, arg)
379 struct keytabent *ktent;
380 char *arg;
382 u_char kbd = 0;
383 u_int kbd2;
384 int i;
386 if (arg) {
387 for (i = 0; i < (int)strlen(arg) - 1; ++i)
388 if (!isdigit((unsigned char)arg[i]))
389 BARF(ktent);
390 kbd2 = atoi(arg);
391 if (kbd2 > 0xff)
392 BARF(ktent);
393 kbd += kbd2;
394 if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
395 FAILEDWRITE(ktent);
396 } else
397 if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
398 FAILEDREAD(ktent);
400 printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
403 static struct strvaltabent constab[] = {
404 { "b&w", EE_CONS_BW },
405 { "ttya", EE_CONS_TTYA },
406 { "ttyb", EE_CONS_TTYB },
407 { "color", EE_CONS_COLOR },
408 { "p4opt", EE_CONS_P4OPT },
409 { NULL, 0 },
412 void
413 ee_constype(ktent, arg)
414 struct keytabent *ktent;
415 char *arg;
417 struct strvaltabent *svp;
418 u_char cons;
420 if (arg) {
421 for (svp = constab; svp->sv_str != NULL; ++svp)
422 if (strcmp(svp->sv_str, arg) == 0)
423 break;
424 if (svp->sv_str == NULL)
425 BARF(ktent);
427 cons = svp->sv_val;
428 if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
429 FAILEDWRITE(ktent);
430 } else {
431 if (doio(ktent, &cons, sizeof(cons), IO_READ))
432 FAILEDREAD(ktent);
434 for (svp = constab; svp->sv_str != NULL; ++svp)
435 if (svp->sv_val == cons)
436 break;
437 if (svp->sv_str == NULL) {
438 warnx("unknown type 0x%x for %s", cons,
439 ktent->kt_keyword);
440 return;
443 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
447 void
448 ee_diagpath(ktent, arg)
449 struct keytabent *ktent;
450 char *arg;
452 char path[40];
454 memset(path, 0, sizeof(path));
455 if (arg) {
456 if (strlen(arg) > sizeof(path))
457 BARF(ktent);
458 memcpy(path, arg, sizeof path);
459 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
460 FAILEDWRITE(ktent);
461 } else
462 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
463 FAILEDREAD(ktent);
465 printf("%s=%s\n", ktent->kt_keyword, path);
468 void
469 ee_banner(ktent, arg)
470 struct keytabent *ktent;
471 char *arg;
473 char string[80];
474 u_char enable;
475 struct keytabent kt;
477 kt.kt_keyword = "enable_banner";
478 kt.kt_offset = EE_BANNER_ENABLE_LOC;
479 kt.kt_handler = ee_notsupp;
481 memset(string, '\0', sizeof(string));
482 if (arg) {
483 if (strlen(arg) > sizeof(string))
484 BARF(ktent);
485 if (*arg != '\0') {
486 enable = EE_TRUE;
487 memcpy(string, arg, sizeof string);
488 if (doio(ktent, (u_char *)string,
489 sizeof(string), IO_WRITE))
490 FAILEDWRITE(ktent);
491 } else {
492 enable = EE_FALSE;
493 if (doio(ktent, (u_char *)string,
494 sizeof(string), IO_READ))
495 FAILEDREAD(ktent);
498 if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
499 FAILEDWRITE(&kt);
500 } else {
501 if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
502 FAILEDREAD(ktent);
503 if (doio(&kt, &enable, sizeof(enable), IO_READ))
504 FAILEDREAD(&kt);
506 printf("%s=%s (%s)\n", ktent->kt_keyword, string,
507 enable == EE_TRUE ? "enabled" : "disabled");
510 /* ARGSUSED */
511 void
512 ee_notsupp(ktent, arg)
513 struct keytabent *ktent;
514 char *arg;
517 warnx("field `%s' not yet supported", ktent->kt_keyword);
520 static void
521 badval(ktent, arg)
522 struct keytabent *ktent;
523 char *arg;
526 warnx("inappropriate value `%s' for field `%s'", arg,
527 ktent->kt_keyword);
530 static int
531 doio(ktent, buf, len, wr)
532 struct keytabent *ktent;
533 u_char *buf;
534 ssize_t len;
535 int wr;
537 int fd, rval = 0;
538 u_char *buf2;
540 buf2 = (u_char *)calloc(1, len);
541 if (buf2 == NULL) {
542 memcpy(err_str, "memory allocation failed", sizeof err_str);
543 return (1);
546 fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
547 if (fd < 0) {
548 (void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
549 strerror(errno));
550 free(buf2);
551 return (1);
554 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
555 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
556 path_eeprom, strerror(errno));
557 rval = 1;
558 goto done;
561 if (read(fd, buf2, len) != len) {
562 (void)snprintf(err_str, sizeof err_str, "read: %s: %s",
563 path_eeprom, strerror(errno));
564 return (1);
567 if (wr == IO_WRITE) {
568 if (memcmp(buf, buf2, len) == 0)
569 goto done;
571 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
572 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
573 path_eeprom, strerror(errno));
574 rval = 1;
575 goto done;
578 ++update_checksums;
579 if (write(fd, buf, len) < 0) {
580 (void)snprintf(err_str, sizeof err_str, "write: %s: %s",
581 path_eeprom, strerror(errno));
582 rval = 1;
583 goto done;
585 } else
586 memmove(buf, buf2, len);
588 done:
589 free(buf2);
590 (void)close(fd);
591 return (rval);
595 * Read from eeLastHwUpdate to just before eeReserved. Calculate
596 * a checksum, and deposit 3 copies of it sequentially starting at
597 * eeChecksum[0]. Increment the write count, and deposit 3 copies
598 * of it sequentially starting at eeWriteCount[0].
600 void
601 ee_updatechecksums()
603 struct keytabent kt;
604 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
605 u_char checksum;
606 int i;
608 kt.kt_keyword = "eeprom contents";
609 kt.kt_offset = EE_HWUPDATE_LOC;
610 kt.kt_handler = ee_notsupp;
612 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
613 cksumfail = 1;
614 FAILEDREAD(&kt);
617 checksum = ee_checksum(checkme, sizeof(checkme));
619 kt.kt_keyword = "eeprom checksum";
620 for (i = 0; i < 4; ++i) {
621 kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
622 if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
623 cksumfail = 1;
624 FAILEDWRITE(&kt);
628 kt.kt_keyword = "eeprom writecount";
629 for (i = 0; i < 4; ++i) {
630 kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
631 if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
632 IO_WRITE)) {
633 cksumfail = 1;
634 FAILEDWRITE(&kt);
639 void
640 ee_verifychecksums()
642 struct keytabent kt;
643 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
644 u_char checksum, ochecksum[3];
645 u_short owritecount[3];
648 * Verify that the EEPROM's write counts match, and update the
649 * global copy for use later.
651 kt.kt_keyword = "eeprom writecount";
652 kt.kt_offset = EE_WC_LOC;
653 kt.kt_handler = ee_notsupp;
655 if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
656 cksumfail = 1;
657 FAILEDREAD(&kt);
660 if (owritecount[0] != owritecount[1] ||
661 owritecount[0] != owritecount[2]) {
662 warnx("eeprom writecount mismatch %s",
663 ignore_checksum ? "(ignoring)" :
664 (fix_checksum ? "(fixing)" : ""));
666 if (!ignore_checksum && !fix_checksum) {
667 cksumfail = 1;
668 return;
671 writecount = MAXIMUM(owritecount[0], owritecount[1]);
672 writecount = MAXIMUM(writecount, owritecount[2]);
673 } else
674 writecount = owritecount[0];
677 * Verify that the EEPROM's checksums match and are correct.
679 kt.kt_keyword = "eeprom checksum";
680 kt.kt_offset = EE_CKSUM_LOC;
682 if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
683 cksumfail = 1;
684 FAILEDREAD(&kt);
687 if (ochecksum[0] != ochecksum[1] ||
688 ochecksum[0] != ochecksum[2]) {
689 warnx("eeprom checksum mismatch %s",
690 ignore_checksum ? "(ignoring)" :
691 (fix_checksum ? "(fixing)" : ""));
693 if (!ignore_checksum && !fix_checksum) {
694 cksumfail = 1;
695 return;
699 kt.kt_keyword = "eeprom contents";
700 kt.kt_offset = EE_HWUPDATE_LOC;
702 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
703 cksumfail = 1;
704 FAILEDREAD(&kt);
707 checksum = ee_checksum(checkme, sizeof(checkme));
709 if (ochecksum[0] != checksum) {
710 warnx("eeprom checksum incorrect %s",
711 ignore_checksum ? "(ignoring)" :
712 (fix_checksum ? "(fixing)" : ""));
714 if (!ignore_checksum && !fix_checksum) {
715 cksumfail = 1;
716 return;
720 if (fix_checksum)
721 ee_updatechecksums();
724 u_char
725 ee_checksum(area, len)
726 u_char *area;
727 size_t len;
729 u_char sum = 0;
731 while (len--)
732 sum += *area++;
734 return (0x100 - sum);