1 /* $NetBSD: eehandlers.c,v 1.14 2008/04/28 20:24:15 martin Exp $ */
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
44 #include <machine/eeprom.h>
46 #include <machine/openpromio.h>
47 #endif /* __sparc__ */
51 extern char *path_eeprom
;
53 extern int update_checksums
;
54 extern int ignore_checksum
;
55 extern int fix_checksum
;
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
},
98 #define FAILEDREAD(kt) { \
99 warnx("%s", err_str); \
100 warnx("failed to read field `%s'", (kt)->kt_keyword); \
105 #define FAILEDWRITE(kt) { \
106 warnx("%s", err_str); \
107 warnx("failed to update field `%s'", (kt)->kt_keyword); \
113 ee_action(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
);
125 warnx("unknown keyword %s", keyword
);
132 struct keytabent
*ktent
;
134 for (ktent
= eekeytab
; ktent
->kt_keyword
!= NULL
; ++ktent
)
135 (*ktent
->kt_handler
)(ktent
, NULL
);
139 ee_hwupdate(ktent
, arg
)
140 struct keytabent
*ktent
;
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");
155 if ((t
= parsedate(arg
, NULL
, NULL
)) == (time_t)(-1))
158 if (doio(ktent
, (u_char
*)&t
, sizeof(t
), IO_WRITE
))
161 if (doio(ktent
, (u_char
*)&t
, sizeof(t
), IO_READ
))
165 if ((cp2
= strrchr(cp
, '\n')) != NULL
)
168 printf("%s=%ld (%s)\n", ktent
->kt_keyword
, (long)t
, cp
);
173 struct keytabent
*ktent
;
181 for (i
= 0; i
< (int)strlen(arg
) - 1; ++i
)
182 if (!isdigit((unsigned char)arg
[i
]))
188 if (doio(ktent
, &num8
, sizeof(num8
), IO_WRITE
))
191 if (doio(ktent
, &num8
, sizeof(num8
), IO_READ
))
194 printf("%s=%d\n", ktent
->kt_keyword
, num8
);
199 struct keytabent
*ktent
;
207 for (i
= 0; i
< (int)strlen(arg
) - 1; ++i
)
208 if (!isdigit((unsigned char)arg
[i
]))
214 if (doio(ktent
, (u_char
*)&num16
, sizeof(num16
), IO_WRITE
))
217 if (doio(ktent
, (u_char
*)&num16
, sizeof(num16
), IO_READ
))
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
},
232 ee_screensize(ktent
, arg
)
233 struct keytabent
*ktent
;
236 struct strvaltabent
*svp
;
240 for (svp
= scrsizetab
; svp
->sv_str
!= NULL
; ++svp
)
241 if (strcmp(svp
->sv_str
, arg
) == 0)
243 if (svp
->sv_str
== NULL
)
246 scsize
= svp
->sv_val
;
247 if (doio(ktent
, &scsize
, sizeof(scsize
), IO_WRITE
))
250 if (doio(ktent
, &scsize
, sizeof(scsize
), IO_READ
))
253 for (svp
= scrsizetab
; svp
->sv_str
!= NULL
; ++svp
)
254 if (svp
->sv_val
== scsize
)
256 if (svp
->sv_str
== NULL
) {
257 warnx("unknown %s value %d", ktent
->kt_keyword
,
262 printf("%s=%s\n", ktent
->kt_keyword
, svp
->sv_str
);
265 static struct strvaltabent truthtab
[] = {
267 { "false", EE_FALSE
},
272 ee_truefalse(ktent
, arg
)
273 struct keytabent
*ktent
;
276 struct strvaltabent
*svp
;
280 for (svp
= truthtab
; svp
->sv_str
!= NULL
; ++svp
)
281 if (strcmp(svp
->sv_str
, arg
) == 0)
283 if (svp
->sv_str
== NULL
)
287 if (doio(ktent
, &truth
, sizeof(truth
), IO_WRITE
))
290 if (doio(ktent
, &truth
, sizeof(truth
), IO_READ
))
293 for (svp
= truthtab
; svp
->sv_str
!= NULL
; ++svp
)
294 if (svp
->sv_val
== truth
)
296 if (svp
->sv_str
== NULL
) {
297 warnx("unknown truth value 0x%x for %s", truth
,
302 printf("%s=%s\n", ktent
->kt_keyword
, svp
->sv_str
);
306 ee_bootdev(ktent
, arg
)
307 struct keytabent
*ktent
;
317 * The format of the string we accept is the following:
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] != ')')
329 /* Handle the first 2 letters. */
330 for (i
= 0; i
< 2; ++i
) {
331 if (arg
[i
] < 'a' || arg
[i
] > 'z')
333 dev
[i
] = (u_char
)arg
[i
];
336 /* Handle the 3 `0x'-less hex values. */
338 for (i
= 2; i
< 5; ++i
) {
342 if (*cp
>= '0' && *cp
<= '9')
343 dev
[i
] = *cp
++ - '0';
344 else if (*cp
>= 'a' && *cp
<= 'f')
345 dev
[i
] = 10 + (*cp
++ - 'a');
349 /* Deal with a second digit. */
350 if (*cp
>= '0' && *cp
<= '9') {
353 dev
[i
] += *cp
++ - '0';
354 } else if (*cp
>= 'a' && *cp
<= 'f') {
357 dev
[i
] += 10 + (*cp
++ - 'a');
360 /* Ensure we have the correct delimiter. */
361 if ((*cp
== ',' && i
< 4) || (*cp
== ')' && i
== 4)) {
367 if (doio(ktent
, (u_char
*)&dev
[0], sizeof(dev
), IO_WRITE
))
370 if (doio(ktent
, (u_char
*)&dev
[0], sizeof(dev
), IO_READ
))
373 printf("%s=%c%c(%x,%x,%x)\n", ktent
->kt_keyword
, dev
[0],
374 dev
[1], dev
[2], dev
[3], dev
[4]);
378 ee_kbdtype(ktent
, arg
)
379 struct keytabent
*ktent
;
387 for (i
= 0; i
< (int)strlen(arg
) - 1; ++i
)
388 if (!isdigit((unsigned char)arg
[i
]))
394 if (doio(ktent
, &kbd
, sizeof(kbd
), IO_WRITE
))
397 if (doio(ktent
, &kbd
, sizeof(kbd
), IO_READ
))
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
},
413 ee_constype(ktent
, arg
)
414 struct keytabent
*ktent
;
417 struct strvaltabent
*svp
;
421 for (svp
= constab
; svp
->sv_str
!= NULL
; ++svp
)
422 if (strcmp(svp
->sv_str
, arg
) == 0)
424 if (svp
->sv_str
== NULL
)
428 if (doio(ktent
, &cons
, sizeof(cons
), IO_WRITE
))
431 if (doio(ktent
, &cons
, sizeof(cons
), IO_READ
))
434 for (svp
= constab
; svp
->sv_str
!= NULL
; ++svp
)
435 if (svp
->sv_val
== cons
)
437 if (svp
->sv_str
== NULL
) {
438 warnx("unknown type 0x%x for %s", cons
,
443 printf("%s=%s\n", ktent
->kt_keyword
, svp
->sv_str
);
448 ee_diagpath(ktent
, arg
)
449 struct keytabent
*ktent
;
454 memset(path
, 0, sizeof(path
));
456 if (strlen(arg
) > sizeof(path
))
458 memcpy(path
, arg
, sizeof path
);
459 if (doio(ktent
, (u_char
*)&path
[0], sizeof(path
), IO_WRITE
))
462 if (doio(ktent
, (u_char
*)&path
[0], sizeof(path
), IO_READ
))
465 printf("%s=%s\n", ktent
->kt_keyword
, path
);
469 ee_banner(ktent
, arg
)
470 struct keytabent
*ktent
;
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
));
483 if (strlen(arg
) > sizeof(string
))
487 memcpy(string
, arg
, sizeof string
);
488 if (doio(ktent
, (u_char
*)string
,
489 sizeof(string
), IO_WRITE
))
493 if (doio(ktent
, (u_char
*)string
,
494 sizeof(string
), IO_READ
))
498 if (doio(&kt
, &enable
, sizeof(enable
), IO_WRITE
))
501 if (doio(ktent
, (u_char
*)string
, sizeof(string
), IO_READ
))
503 if (doio(&kt
, &enable
, sizeof(enable
), IO_READ
))
506 printf("%s=%s (%s)\n", ktent
->kt_keyword
, string
,
507 enable
== EE_TRUE
? "enabled" : "disabled");
512 ee_notsupp(ktent
, arg
)
513 struct keytabent
*ktent
;
517 warnx("field `%s' not yet supported", ktent
->kt_keyword
);
522 struct keytabent
*ktent
;
526 warnx("inappropriate value `%s' for field `%s'", arg
,
531 doio(ktent
, buf
, len
, wr
)
532 struct keytabent
*ktent
;
540 buf2
= (u_char
*)calloc(1, len
);
542 memcpy(err_str
, "memory allocation failed", sizeof err_str
);
546 fd
= open(path_eeprom
, wr
== IO_WRITE
? O_RDWR
: O_RDONLY
, 0640);
548 (void)snprintf(err_str
, sizeof err_str
, "open: %s: %s", path_eeprom
,
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
));
561 if (read(fd
, buf2
, len
) != len
) {
562 (void)snprintf(err_str
, sizeof err_str
, "read: %s: %s",
563 path_eeprom
, strerror(errno
));
567 if (wr
== IO_WRITE
) {
568 if (memcmp(buf
, buf2
, len
) == 0)
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
));
579 if (write(fd
, buf
, len
) < 0) {
580 (void)snprintf(err_str
, sizeof err_str
, "write: %s: %s",
581 path_eeprom
, strerror(errno
));
586 memmove(buf
, buf2
, len
);
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].
604 u_char checkme
[EE_SIZE
- EE_HWUPDATE_LOC
];
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
)) {
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
)) {
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
),
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
)) {
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
) {
671 writecount
= MAXIMUM(owritecount
[0], owritecount
[1]);
672 writecount
= MAXIMUM(writecount
, owritecount
[2]);
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
)) {
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
) {
699 kt
.kt_keyword
= "eeprom contents";
700 kt
.kt_offset
= EE_HWUPDATE_LOC
;
702 if (doio(&kt
, checkme
, sizeof(checkme
), IO_READ
)) {
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
) {
721 ee_updatechecksums();
725 ee_checksum(area
, len
)
734 return (0x100 - sum
);