Home | History | Annotate | Line # | Download | only in eeprom
eehandlers.c revision 1.10
      1 /*	$NetBSD: eehandlers.c,v 1.10 2004/11/08 08:05:20 dsl Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/types.h>
     40 #include <ctype.h>
     41 #include <err.h>
     42 #include <errno.h>
     43 #include <fcntl.h>
     44 #include <string.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 #include <time.h>
     49 #include <unistd.h>
     50 
     51 #include <machine/eeprom.h>
     52 #ifdef __sparc__
     53 #include <machine/openpromio.h>
     54 #endif /* __sparc__ */
     55 
     56 #include "defs.h"
     57 
     58 extern	char *path_eeprom;
     59 extern	int eval;
     60 extern	int update_checksums;
     61 extern	int ignore_checksum;
     62 extern	int fix_checksum;
     63 extern	int cksumfail;
     64 extern	u_short writecount;
     65 
     66 struct	timeb;
     67 extern	time_t get_date (char *, struct timeb *);
     68 
     69 static	char err_str[BUFSIZE];
     70 
     71 static	void badval (struct keytabent *, char *);
     72 static	int doio (struct keytabent *, u_char *, ssize_t, int);
     73 
     74 struct	keytabent eekeytab[] = {
     75 	{ "hwupdate",		0x10,	ee_hwupdate },
     76 	{ "memsize",		0x14,	ee_num8 },
     77 	{ "memtest",		0x15,	ee_num8 },
     78 	{ "scrsize",		0x16,	ee_screensize },
     79 	{ "watchdog_reboot",	0x17,	ee_truefalse },
     80 	{ "default_boot",	0x18,	ee_truefalse },
     81 	{ "bootdev",		0x19,	ee_bootdev },
     82 	{ "kbdtype",		0x1e,	ee_kbdtype },
     83 	{ "console",		0x1f,	ee_constype },
     84 	{ "keyclick",		0x21,	ee_truefalse },
     85 	{ "diagdev",		0x22,	ee_bootdev },
     86 	{ "diagpath",		0x28,	ee_diagpath },
     87 	{ "columns",		0x50,	ee_num8 },
     88 	{ "rows",		0x51,	ee_num8 },
     89 	{ "ttya_use_baud",	0x58,	ee_truefalse },
     90 	{ "ttya_baud",		0x59,	ee_num16 },
     91 	{ "ttya_no_rtsdtr",	0x5b,	ee_truefalse },
     92 	{ "ttyb_use_baud",	0x60,	ee_truefalse },
     93 	{ "ttyb_baud",		0x61,	ee_num16 },
     94 	{ "ttyb_no_rtsdtr",	0x63,	ee_truefalse },
     95 	{ "banner",		0x68,	ee_banner },
     96 	{ "secure",		0,	ee_notsupp },
     97 	{ "bad_login",		0,	ee_notsupp },
     98 	{ "password",		0,	ee_notsupp },
     99 	{ NULL,			0,	ee_notsupp },
    100 };
    101 
    102 #define BARF(kt) {							\
    103 	badval((kt), arg);						\
    104 	++eval;								\
    105 	return;								\
    106 }
    107 
    108 #define FAILEDREAD(kt) {						\
    109 	warnx("%s", err_str);						\
    110 	warnx("failed to read field `%s'", (kt)->kt_keyword);		\
    111 	++eval;								\
    112 	return;								\
    113 }
    114 
    115 #define FAILEDWRITE(kt) {						\
    116 	warnx("%s", err_str);						\
    117 	warnx("failed to update field `%s'", (kt)->kt_keyword);		\
    118 	++eval;								\
    119 	return;								\
    120 }
    121 
    122 void
    123 ee_action(keyword, arg)
    124 	char *keyword, *arg;
    125 {
    126 	struct keytabent *ktent;
    127 
    128 	for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
    129 		if (strcmp(ktent->kt_keyword, keyword) == 0) {
    130 			(*ktent->kt_handler)(ktent, arg);
    131 			return;
    132 		}
    133 	}
    134 
    135 	warnx("unknown keyword %s", keyword);
    136 	++eval;
    137 }
    138 
    139 void
    140 ee_dump()
    141 {
    142 	struct keytabent *ktent;
    143 
    144 	for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
    145 		(*ktent->kt_handler)(ktent, NULL);
    146 }
    147 
    148 void
    149 ee_hwupdate(ktent, arg)
    150 	struct keytabent *ktent;
    151 	char *arg;
    152 {
    153 	time_t t;
    154 	char *cp, *cp2;
    155 
    156 	if (arg) {
    157 		if ((strcmp(arg, "now") == 0) ||
    158 		    (strcmp(arg, "today") == 0)) {
    159 			if ((t = time(NULL)) == (time_t)(-1)) {
    160 				warnx("can't get current time");
    161 				++eval;
    162 				return;
    163 			}
    164 		} else
    165 			if ((t = get_date(arg, NULL)) == (time_t)(-1))
    166 				BARF(ktent);
    167 
    168 		if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
    169 			FAILEDWRITE(ktent);
    170 	} else
    171 		if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
    172 			FAILEDREAD(ktent);
    173 
    174 	cp = ctime(&t);
    175 	if ((cp2 = strrchr(cp, '\n')) != NULL)
    176 		*cp2 = '\0';
    177 
    178 	printf("%s=%ld (%s)\n", ktent->kt_keyword, (long)t, cp);
    179 }
    180 
    181 void
    182 ee_num8(ktent, arg)
    183 	struct keytabent *ktent;
    184 	char *arg;
    185 {
    186 	u_char num8 = 0;
    187 	u_int num32;
    188 	int i;
    189 
    190 	if (arg) {
    191 		for (i = 0; i < (strlen(arg) - 1); ++i)
    192 			if (!isdigit((unsigned char)arg[i]))
    193 				BARF(ktent);
    194 		num32 = atoi(arg);
    195 		if (num32 > 0xff)
    196 			BARF(ktent);
    197 		num8 += num32;
    198 		if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
    199 			FAILEDWRITE(ktent);
    200 	} else
    201 		if (doio(ktent, &num8, sizeof(num8), IO_READ))
    202 			FAILEDREAD(ktent);
    203 
    204 	printf("%s=%d\n", ktent->kt_keyword, num8);
    205 }
    206 
    207 void
    208 ee_num16(ktent, arg)
    209 	struct keytabent *ktent;
    210 	char *arg;
    211 {
    212 	u_int16_t num16 = 0;
    213 	u_int num32;
    214 	int i;
    215 
    216 	if (arg) {
    217 		for (i = 0; i < (strlen(arg) - 1); ++i)
    218 			if (!isdigit((unsigned char)arg[i]))
    219 				BARF(ktent);
    220 		num32 = atoi(arg);
    221 		if (num32 > 0xffff)
    222 			BARF(ktent);
    223 		num16 += num32;
    224 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
    225 			FAILEDWRITE(ktent);
    226 	} else
    227 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
    228 			FAILEDREAD(ktent);
    229 
    230 	printf("%s=%d\n", ktent->kt_keyword, num16);
    231 }
    232 
    233 static	struct strvaltabent scrsizetab[] = {
    234 	{ "1152x900",		EE_SCR_1152X900 },
    235 	{ "1024x1024",		EE_SCR_1024X1024 },
    236 	{ "1600x1280",		EE_SCR_1600X1280 },
    237 	{ "1440x1440",		EE_SCR_1440X1440 },
    238 	{ NULL,			0 },
    239 };
    240 
    241 void
    242 ee_screensize(ktent, arg)
    243 	struct keytabent *ktent;
    244 	char *arg;
    245 {
    246 	struct strvaltabent *svp;
    247 	u_char scsize;
    248 
    249 	if (arg) {
    250 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
    251 			if (strcmp(svp->sv_str, arg) == 0)
    252 				break;
    253 		if (svp->sv_str == NULL)
    254 			BARF(ktent);
    255 
    256 		scsize = svp->sv_val;
    257 		if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
    258 			FAILEDWRITE(ktent);
    259 	} else {
    260 		if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
    261 			FAILEDREAD(ktent);
    262 
    263 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
    264 			if (svp->sv_val == scsize)
    265 				break;
    266 		if (svp->sv_str == NULL) {
    267 			warnx("unknown %s value %d", ktent->kt_keyword,
    268 			    scsize);
    269 			return;
    270 		}
    271 	}
    272 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
    273 }
    274 
    275 static	struct strvaltabent truthtab[] = {
    276 	{ "true",		EE_TRUE },
    277 	{ "false",		EE_FALSE },
    278 	{ NULL,			0 },
    279 };
    280 
    281 void
    282 ee_truefalse(ktent, arg)
    283 	struct keytabent *ktent;
    284 	char *arg;
    285 {
    286 	struct strvaltabent *svp;
    287 	u_char truth;
    288 
    289 	if (arg) {
    290 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
    291 			if (strcmp(svp->sv_str, arg) == 0)
    292 				break;
    293 		if (svp->sv_str == NULL)
    294 			BARF(ktent);
    295 
    296 		truth = svp->sv_val;
    297 		if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
    298 			FAILEDWRITE(ktent);
    299 	} else {
    300 		if (doio(ktent, &truth, sizeof(truth), IO_READ))
    301 			FAILEDREAD(ktent);
    302 
    303 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
    304 			if (svp->sv_val == truth)
    305 				break;
    306 		if (svp->sv_str == NULL) {
    307 			warnx("unknown truth value 0x%x for %s", truth,
    308 			    ktent->kt_keyword);
    309 			return;
    310 		}
    311 	}
    312 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
    313 }
    314 
    315 void
    316 ee_bootdev(ktent, arg)
    317 	struct keytabent *ktent;
    318 	char *arg;
    319 {
    320 	u_char dev[5];
    321 	int i;
    322 	size_t arglen;
    323 	char *cp;
    324 
    325 	if (arg) {
    326 		/*
    327 		 * The format of the string we accept is the following:
    328 		 *	cc(n,n,n)
    329 		 * where:
    330 		 *	c -- an alphabetical character [a-z]
    331 		 *	n -- a number in hexadecimal, between 0 and ff,
    332 		 *	     with no leading `0x'.
    333 		 */
    334 		arglen = strlen(arg);
    335 		if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
    336 		     arg[arglen - 1] != ')')
    337 			BARF(ktent);
    338 
    339 		/* Handle the first 2 letters. */
    340 		for (i = 0; i < 2; ++i) {
    341 			if (arg[i] < 'a' || arg[i] > 'z')
    342 				BARF(ktent);
    343 			dev[i] = (u_char)arg[i];
    344 		}
    345 
    346 		/* Handle the 3 `0x'-less hex values. */
    347 		cp = &arg[3];
    348 		for (i = 2; i < 5; ++i) {
    349 			if (*cp == '\0')
    350 				BARF(ktent);
    351 
    352 			if (*cp >= '0' && *cp <= '9')
    353 				dev[i] = *cp++ - '0';
    354 			else if (*cp >= 'a' && *cp <= 'f')
    355 				dev[i] = 10 + (*cp++ - 'a');
    356 			else
    357 				BARF(ktent);
    358 
    359 			/* Deal with a second digit. */
    360 			if (*cp >= '0' && *cp <= '9') {
    361 				dev[i] <<= 4;
    362 				dev[i] &= 0xf0;
    363 				dev[i] += *cp++ - '0';
    364 			} else if (*cp >= 'a' && *cp <= 'f') {
    365 				dev[i] <<= 4;
    366 				dev[i] &= 0xf0;
    367 				dev[i] += 10 + (*cp++ - 'a');
    368 			}
    369 
    370 			/* Ensure we have the correct delimiter. */
    371 			if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
    372 				++cp;
    373 				continue;
    374 			} else
    375 				BARF(ktent);
    376 		}
    377 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
    378 			FAILEDWRITE(ktent);
    379 	} else
    380 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
    381 			FAILEDREAD(ktent);
    382 
    383 	printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
    384 	     dev[1], dev[2], dev[3], dev[4]);
    385 }
    386 
    387 void
    388 ee_kbdtype(ktent, arg)
    389 	struct keytabent *ktent;
    390 	char *arg;
    391 {
    392 	u_char kbd = 0;
    393 	u_int kbd2;
    394 	int i;
    395 
    396 	if (arg) {
    397 		for (i = 0; i < (strlen(arg) - 1); ++i)
    398 			if (!isdigit((unsigned char)arg[i]))
    399 				BARF(ktent);
    400 		kbd2 = atoi(arg);
    401 		if (kbd2 > 0xff)
    402 			BARF(ktent);
    403 		kbd += kbd2;
    404 		if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
    405 			FAILEDWRITE(ktent);
    406 	} else
    407 		if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
    408 			FAILEDREAD(ktent);
    409 
    410 	printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
    411 }
    412 
    413 static	struct strvaltabent constab[] = {
    414 	{ "b&w",		EE_CONS_BW },
    415 	{ "ttya",		EE_CONS_TTYA },
    416 	{ "ttyb",		EE_CONS_TTYB },
    417 	{ "color",		EE_CONS_COLOR },
    418 	{ "p4opt",		EE_CONS_P4OPT },
    419 	{ NULL,			0 },
    420 };
    421 
    422 void
    423 ee_constype(ktent, arg)
    424 	struct keytabent *ktent;
    425 	char *arg;
    426 {
    427 	struct strvaltabent *svp;
    428 	u_char cons;
    429 
    430 	if (arg) {
    431 		for (svp = constab; svp->sv_str != NULL; ++svp)
    432 			if (strcmp(svp->sv_str, arg) == 0)
    433 				break;
    434 		if (svp->sv_str == NULL)
    435 			BARF(ktent);
    436 
    437 		cons = svp->sv_val;
    438 		if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
    439 			FAILEDWRITE(ktent);
    440 	} else {
    441 		if (doio(ktent, &cons, sizeof(cons), IO_READ))
    442 			FAILEDREAD(ktent);
    443 
    444 		for (svp = constab; svp->sv_str != NULL; ++svp)
    445 			if (svp->sv_val == cons)
    446 				break;
    447 		if (svp->sv_str == NULL) {
    448 			warnx("unknown type 0x%x for %s", cons,
    449 			    ktent->kt_keyword);
    450 			return;
    451 		}
    452 	}
    453 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
    454 
    455 }
    456 
    457 void
    458 ee_diagpath(ktent, arg)
    459 	struct keytabent *ktent;
    460 	char *arg;
    461 {
    462 	char path[40];
    463 
    464 	memset(path, 0, sizeof(path));
    465 	if (arg) {
    466 		if (strlen(arg) > sizeof(path))
    467 			BARF(ktent);
    468 		memcpy(path, arg, sizeof path);
    469 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
    470 			FAILEDWRITE(ktent);
    471 	} else
    472 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
    473 			FAILEDREAD(ktent);
    474 
    475 	printf("%s=%s\n", ktent->kt_keyword, path);
    476 }
    477 
    478 void
    479 ee_banner(ktent, arg)
    480 	struct keytabent *ktent;
    481 	char *arg;
    482 {
    483 	char string[80];
    484 	u_char enable;
    485 	struct keytabent kt;
    486 
    487 	kt.kt_keyword = "enable_banner";
    488 	kt.kt_offset = EE_BANNER_ENABLE_LOC;
    489 	kt.kt_handler = ee_notsupp;
    490 
    491 	memset(string, '\0', sizeof(string));
    492 	if (arg) {
    493 		if (strlen(arg) > sizeof(string))
    494 			BARF(ktent);
    495 		if (*arg != '\0') {
    496 			enable = EE_TRUE;
    497 			memcpy(string, arg, sizeof string);
    498 			if (doio(ktent, (u_char *)string,
    499 			    sizeof(string), IO_WRITE))
    500 				FAILEDWRITE(ktent);
    501 		} else {
    502 			enable = EE_FALSE;
    503 			if (doio(ktent, (u_char *)string,
    504 			    sizeof(string), IO_READ))
    505 				FAILEDREAD(ktent);
    506 		}
    507 
    508 		if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
    509 			FAILEDWRITE(&kt);
    510 	} else {
    511 		if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
    512 			FAILEDREAD(ktent);
    513 		if (doio(&kt, &enable, sizeof(enable), IO_READ))
    514 			FAILEDREAD(&kt);
    515 	}
    516 	printf("%s=%s (%s)\n", ktent->kt_keyword, string,
    517 	    enable == EE_TRUE ? "enabled" : "disabled");
    518 }
    519 
    520 /* ARGSUSED */
    521 void
    522 ee_notsupp(ktent, arg)
    523 	struct keytabent *ktent;
    524 	char *arg;
    525 {
    526 
    527 	warnx("field `%s' not yet supported", ktent->kt_keyword);
    528 }
    529 
    530 static void
    531 badval(ktent, arg)
    532 	struct keytabent *ktent;
    533 	char *arg;
    534 {
    535 
    536 	warnx("inappropriate value `%s' for field `%s'", arg,
    537 	    ktent->kt_keyword);
    538 }
    539 
    540 static int
    541 doio(ktent, buf, len, wr)
    542 	struct keytabent *ktent;
    543 	u_char *buf;
    544 	ssize_t len;
    545 	int wr;
    546 {
    547 	int fd, rval = 0;
    548 	u_char *buf2;
    549 
    550 	buf2 = (u_char *)calloc(1, len);
    551 	if (buf2 == NULL) {
    552 		memcpy(err_str, "memory allocation failed", sizeof err_str);
    553 		return (1);
    554 	}
    555 
    556 	fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
    557 	if (fd < 0) {
    558 		(void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
    559 		    strerror(errno));
    560 		free(buf2);
    561 		return (1);
    562 	}
    563 
    564 	if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
    565 		(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
    566 		    path_eeprom, strerror(errno));
    567 		rval = 1;
    568 		goto done;
    569 	}
    570 
    571 	if (read(fd, buf2, len) != len) {
    572 		(void)snprintf(err_str, sizeof err_str, "read: %s: %s",
    573 		    path_eeprom, strerror(errno));
    574 		return (1);
    575 	}
    576 
    577 	if (wr == IO_WRITE) {
    578 		if (memcmp(buf, buf2, len) == 0)
    579 			goto done;
    580 
    581 		if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
    582 			(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
    583 			    path_eeprom, strerror(errno));
    584 			rval = 1;
    585 			goto done;
    586 		}
    587 
    588 		++update_checksums;
    589 		if (write(fd, buf, len) < 0) {
    590 			(void)snprintf(err_str, sizeof err_str, "write: %s: %s",
    591 			    path_eeprom, strerror(errno));
    592 			rval = 1;
    593 			goto done;
    594 		}
    595 	} else
    596 		memmove(buf, buf2, len);
    597 
    598  done:
    599 	free(buf2);
    600 	(void)close(fd);
    601 	return (rval);
    602 }
    603 
    604 /*
    605  * Read from eeLastHwUpdate to just before eeReserved.  Calculate
    606  * a checksum, and deposit 3 copies of it sequentially starting at
    607  * eeChecksum[0].  Increment the write count, and deposit 3 copies
    608  * of it sequentially starting at eeWriteCount[0].
    609  */
    610 void
    611 ee_updatechecksums()
    612 {
    613 	struct keytabent kt;
    614 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
    615 	u_char checksum;
    616 	int i;
    617 
    618 	kt.kt_keyword = "eeprom contents";
    619 	kt.kt_offset = EE_HWUPDATE_LOC;
    620 	kt.kt_handler = ee_notsupp;
    621 
    622 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
    623 		cksumfail = 1;
    624 		FAILEDREAD(&kt);
    625 	}
    626 
    627 	checksum = ee_checksum(checkme, sizeof(checkme));
    628 
    629 	kt.kt_keyword = "eeprom checksum";
    630 	for (i = 0; i < 4; ++i) {
    631 		kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
    632 		if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
    633 			cksumfail = 1;
    634 			FAILEDWRITE(&kt);
    635 		}
    636 	}
    637 
    638 	kt.kt_keyword = "eeprom writecount";
    639 	for (i = 0; i < 4; ++i) {
    640 		kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
    641 		if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
    642 		    IO_WRITE)) {
    643 			cksumfail = 1;
    644 			FAILEDWRITE(&kt);
    645 		}
    646 	}
    647 }
    648 
    649 void
    650 ee_verifychecksums()
    651 {
    652 	struct keytabent kt;
    653 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
    654 	u_char checksum, ochecksum[3];
    655 	u_short owritecount[3];
    656 
    657 	/*
    658 	 * Verify that the EEPROM's write counts match, and update the
    659 	 * global copy for use later.
    660 	 */
    661 	kt.kt_keyword = "eeprom writecount";
    662 	kt.kt_offset = EE_WC_LOC;
    663 	kt.kt_handler = ee_notsupp;
    664 
    665 	if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
    666 		cksumfail = 1;
    667 		FAILEDREAD(&kt);
    668 	}
    669 
    670 	if (owritecount[0] != owritecount[1] ||
    671 	    owritecount[0] != owritecount[2]) {
    672 		warnx("eeprom writecount mismatch %s",
    673 		    ignore_checksum ? "(ignoring)" :
    674 		    (fix_checksum ? "(fixing)" : ""));
    675 
    676 		if (!ignore_checksum && !fix_checksum) {
    677 			cksumfail = 1;
    678 			return;
    679 		}
    680 
    681 		writecount = MAXIMUM(owritecount[0], owritecount[1]);
    682 		writecount = MAXIMUM(writecount, owritecount[2]);
    683 	} else
    684 		writecount = owritecount[0];
    685 
    686 	/*
    687 	 * Verify that the EEPROM's checksums match and are correct.
    688 	 */
    689 	kt.kt_keyword = "eeprom checksum";
    690 	kt.kt_offset = EE_CKSUM_LOC;
    691 
    692 	if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
    693 		cksumfail = 1;
    694 		FAILEDREAD(&kt);
    695 	}
    696 
    697 	if (ochecksum[0] != ochecksum[1] ||
    698 	    ochecksum[0] != ochecksum[2]) {
    699 		warnx("eeprom checksum mismatch %s",
    700 		    ignore_checksum ? "(ignoring)" :
    701 		    (fix_checksum ? "(fixing)" : ""));
    702 
    703 		if (!ignore_checksum && !fix_checksum) {
    704 			cksumfail = 1;
    705 			return;
    706 		}
    707 	}
    708 
    709 	kt.kt_keyword = "eeprom contents";
    710 	kt.kt_offset = EE_HWUPDATE_LOC;
    711 
    712 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
    713 		cksumfail = 1;
    714 		FAILEDREAD(&kt);
    715 	}
    716 
    717 	checksum = ee_checksum(checkme, sizeof(checkme));
    718 
    719 	if (ochecksum[0] != checksum) {
    720 		warnx("eeprom checksum incorrect %s",
    721 		    ignore_checksum ? "(ignoring)" :
    722 		    (fix_checksum ? "(fixing)" : ""));
    723 
    724 		if (!ignore_checksum && !fix_checksum) {
    725 			cksumfail = 1;
    726 			return;
    727 		}
    728 	}
    729 
    730 	if (fix_checksum)
    731 		ee_updatechecksums();
    732 }
    733 
    734 u_char
    735 ee_checksum(area, len)
    736 	u_char *area;
    737 	size_t len;
    738 {
    739 	u_char sum = 0;
    740 
    741 	while (len--)
    742 		sum += *area++;
    743 
    744 	return (0x100 - sum);
    745 }
    746