1 /* $NetBSD: eehandlers.c,v 1.6 1997/10/18 08:40:40 lukem 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 __P((char *, struct timeb *)); 68 69 static char err_str[BUFSIZE]; 70 71 static void badval __P((struct keytabent *, char *)); 72 static int doio __P((struct keytabent *, u_char *, ssize_t, int)); 73 74 #define BARF(kt) { \ 75 badval((kt), arg); \ 76 ++eval; \ 77 return; \ 78 } 79 80 #define FAILEDREAD(kt) { \ 81 warnx(err_str); \ 82 warnx("failed to read field `%s'", (kt)->kt_keyword); \ 83 ++eval; \ 84 return; \ 85 } 86 87 #define FAILEDWRITE(kt) { \ 88 warnx(err_str); \ 89 warnx("failed to update field `%s'", (kt)->kt_keyword); \ 90 ++eval; \ 91 return; \ 92 } 93 94 void 95 ee_hwupdate(ktent, arg) 96 struct keytabent *ktent; 97 char *arg; 98 { 99 time_t t; 100 char *cp, *cp2; 101 102 if (arg) { 103 if ((strcmp(arg, "now") == 0) || 104 (strcmp(arg, "today") == 0)) { 105 if ((t = time(NULL)) == (time_t)(-1)) { 106 warnx("can't get current time"); 107 ++eval; 108 return; 109 } 110 } else 111 if ((t = get_date(arg, NULL)) == (time_t)(-1)) 112 BARF(ktent); 113 114 if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE)) 115 FAILEDWRITE(ktent); 116 } else 117 if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ)) 118 FAILEDREAD(ktent); 119 120 cp = ctime(&t); 121 if ((cp2 = strrchr(cp, '\n')) != NULL) 122 *cp2 = '\0'; 123 124 printf("%s=%ld (%s)\n", ktent->kt_keyword, (long)t, cp); 125 } 126 127 void 128 ee_num8(ktent, arg) 129 struct keytabent *ktent; 130 char *arg; 131 { 132 u_char num8 = 0; 133 u_int num32; 134 int i; 135 136 if (arg) { 137 for (i = 0; i < (strlen(arg) - 1); ++i) 138 if (!isdigit(arg[i])) 139 BARF(ktent); 140 num32 = atoi(arg); 141 if (num32 > 0xff) 142 BARF(ktent); 143 num8 += num32; 144 if (doio(ktent, &num8, sizeof(num8), IO_WRITE)) 145 FAILEDWRITE(ktent); 146 } else 147 if (doio(ktent, &num8, sizeof(num8), IO_READ)) 148 FAILEDREAD(ktent); 149 150 printf("%s=%d\n", ktent->kt_keyword, num8); 151 } 152 153 void 154 ee_num16(ktent, arg) 155 struct keytabent *ktent; 156 char *arg; 157 { 158 u_int16_t num16 = 0; 159 u_int num32; 160 int i; 161 162 if (arg) { 163 for (i = 0; i < (strlen(arg) - 1); ++i) 164 if (!isdigit(arg[i])) 165 BARF(ktent); 166 num32 = atoi(arg); 167 if (num32 > 0xffff) 168 BARF(ktent); 169 num16 += num32; 170 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE)) 171 FAILEDWRITE(ktent); 172 } else 173 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ)) 174 FAILEDREAD(ktent); 175 176 printf("%s=%d\n", ktent->kt_keyword, num16); 177 } 178 179 static struct strvaltabent scrsizetab[] = { 180 { "1152x900", EE_SCR_1152X900 }, 181 { "1024x1024", EE_SCR_1024X1024 }, 182 { "1600x1280", EE_SCR_1600X1280 }, 183 { "1440x1440", EE_SCR_1440X1440 }, 184 { NULL, 0 }, 185 }; 186 187 void 188 ee_screensize(ktent, arg) 189 struct keytabent *ktent; 190 char *arg; 191 { 192 struct strvaltabent *svp; 193 u_char scsize; 194 195 if (arg) { 196 for (svp = scrsizetab; svp->sv_str != NULL; ++svp) 197 if (strcmp(svp->sv_str, arg) == 0) 198 break; 199 if (svp->sv_str == NULL) 200 BARF(ktent); 201 202 scsize = svp->sv_val; 203 if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE)) 204 FAILEDWRITE(ktent); 205 } else { 206 if (doio(ktent, &scsize, sizeof(scsize), IO_READ)) 207 FAILEDREAD(ktent); 208 209 for (svp = scrsizetab; svp->sv_str != NULL; ++svp) 210 if (svp->sv_val == scsize) 211 break; 212 if (svp->sv_str == NULL) { 213 warnx("unknown %s value %d", ktent->kt_keyword, 214 scsize); 215 return; 216 } 217 } 218 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str); 219 } 220 221 static struct strvaltabent truthtab[] = { 222 { "true", EE_TRUE }, 223 { "false", EE_FALSE }, 224 { NULL, 0 }, 225 }; 226 227 void 228 ee_truefalse(ktent, arg) 229 struct keytabent *ktent; 230 char *arg; 231 { 232 struct strvaltabent *svp; 233 u_char truth; 234 235 if (arg) { 236 for (svp = truthtab; svp->sv_str != NULL; ++svp) 237 if (strcmp(svp->sv_str, arg) == 0) 238 break; 239 if (svp->sv_str == NULL) 240 BARF(ktent); 241 242 truth = svp->sv_val; 243 if (doio(ktent, &truth, sizeof(truth), IO_WRITE)) 244 FAILEDWRITE(ktent); 245 } else { 246 if (doio(ktent, &truth, sizeof(truth), IO_READ)) 247 FAILEDREAD(ktent); 248 249 for (svp = truthtab; svp->sv_str != NULL; ++svp) 250 if (svp->sv_val == truth) 251 break; 252 if (svp->sv_str == NULL) { 253 warnx("unknown truth value 0x%x for %s", truth, 254 ktent->kt_keyword); 255 return; 256 } 257 } 258 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str); 259 } 260 261 void 262 ee_bootdev(ktent, arg) 263 struct keytabent *ktent; 264 char *arg; 265 { 266 u_char dev[5]; 267 int i; 268 size_t arglen; 269 char *cp; 270 271 if (arg) { 272 /* 273 * The format of the string we accept is the following: 274 * cc(n,n,n) 275 * where: 276 * c -- an alphabetical character [a-z] 277 * n -- a number in hexadecimal, between 0 and ff, 278 * with no leading `0x'. 279 */ 280 arglen = strlen(arg); 281 if (arglen < 9 || arglen > 12 || arg[2] != '(' || 282 arg[arglen - 1] != ')') 283 BARF(ktent); 284 285 /* Handle the first 2 letters. */ 286 for (i = 0; i < 2; ++i) { 287 if (arg[i] < 'a' || arg[i] > 'z') 288 BARF(ktent); 289 dev[i] = (u_char)arg[i]; 290 } 291 292 /* Handle the 3 `0x'-less hex values. */ 293 cp = &arg[3]; 294 for (i = 2; i < 5; ++i) { 295 if (*cp == '\0') 296 BARF(ktent); 297 298 if (*cp >= '0' && *cp <= '9') 299 dev[i] = *cp++ - '0'; 300 else if (*cp >= 'a' && *cp <= 'f') 301 dev[i] = 10 + (*cp++ - 'a'); 302 else 303 BARF(ktent); 304 305 /* Deal with a second digit. */ 306 if (*cp >= '0' && *cp <= '9') { 307 dev[i] <<= 4; 308 dev[i] &= 0xf0; 309 dev[i] += *cp++ - '0'; 310 } else if (*cp >= 'a' && *cp <= 'f') { 311 dev[i] <<= 4; 312 dev[i] &= 0xf0; 313 dev[i] += 10 + (*cp++ - 'a'); 314 } 315 316 /* Ensure we have the correct delimiter. */ 317 if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) { 318 ++cp; 319 continue; 320 } else 321 BARF(ktent); 322 } 323 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE)) 324 FAILEDWRITE(ktent); 325 } else 326 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ)) 327 FAILEDREAD(ktent); 328 329 printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0], 330 dev[1], dev[2], dev[3], dev[4]); 331 } 332 333 void 334 ee_kbdtype(ktent, arg) 335 struct keytabent *ktent; 336 char *arg; 337 { 338 u_char kbd = 0; 339 u_int kbd2; 340 int i; 341 342 if (arg) { 343 for (i = 0; i < (strlen(arg) - 1); ++i) 344 if (!isdigit(arg[i])) 345 BARF(ktent); 346 kbd2 = atoi(arg); 347 if (kbd2 > 0xff) 348 BARF(ktent); 349 kbd += kbd2; 350 if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE)) 351 FAILEDWRITE(ktent); 352 } else 353 if (doio(ktent, &kbd, sizeof(kbd), IO_READ)) 354 FAILEDREAD(ktent); 355 356 printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun"); 357 } 358 359 static struct strvaltabent constab[] = { 360 { "b&w", EE_CONS_BW }, 361 { "ttya", EE_CONS_TTYA }, 362 { "ttyb", EE_CONS_TTYB }, 363 { "color", EE_CONS_COLOR }, 364 { "p4opt", EE_CONS_P4OPT }, 365 { NULL, 0 }, 366 }; 367 368 void 369 ee_constype(ktent, arg) 370 struct keytabent *ktent; 371 char *arg; 372 { 373 struct strvaltabent *svp; 374 u_char cons; 375 376 if (arg) { 377 for (svp = constab; svp->sv_str != NULL; ++svp) 378 if (strcmp(svp->sv_str, arg) == 0) 379 break; 380 if (svp->sv_str == NULL) 381 BARF(ktent); 382 383 cons = svp->sv_val; 384 if (doio(ktent, &cons, sizeof(cons), IO_WRITE)) 385 FAILEDWRITE(ktent); 386 } else { 387 if (doio(ktent, &cons, sizeof(cons), IO_READ)) 388 FAILEDREAD(ktent); 389 390 for (svp = constab; svp->sv_str != NULL; ++svp) 391 if (svp->sv_val == cons) 392 break; 393 if (svp->sv_str == NULL) { 394 warnx("unknown type 0x%x for %s", cons, 395 ktent->kt_keyword); 396 return; 397 } 398 } 399 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str); 400 401 } 402 403 void 404 ee_diagpath(ktent, arg) 405 struct keytabent *ktent; 406 char *arg; 407 { 408 char path[40]; 409 410 memset(path, 0, sizeof(path)); 411 if (arg) { 412 if (strlen(arg) > sizeof(path)) 413 BARF(ktent); 414 memcpy(path, arg, sizeof path); 415 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE)) 416 FAILEDWRITE(ktent); 417 } else 418 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ)) 419 FAILEDREAD(ktent); 420 421 printf("%s=%s\n", ktent->kt_keyword, path); 422 } 423 424 void 425 ee_banner(ktent, arg) 426 struct keytabent *ktent; 427 char *arg; 428 { 429 char string[80]; 430 u_char enable; 431 struct keytabent kt; 432 433 kt.kt_keyword = "enable_banner"; 434 kt.kt_offset = EE_BANNER_ENABLE_LOC; 435 kt.kt_handler = ee_notsupp; 436 437 memset(string, '\0', sizeof(string)); 438 if (arg) { 439 if (strlen(arg) > sizeof(string)) 440 BARF(ktent); 441 if (*arg != '\0') { 442 enable = EE_TRUE; 443 memcpy(string, arg, sizeof string); 444 if (doio(ktent, (u_char *)string, 445 sizeof(string), IO_WRITE)) 446 FAILEDWRITE(ktent); 447 } else { 448 enable = EE_FALSE; 449 if (doio(ktent, (u_char *)string, 450 sizeof(string), IO_READ)) 451 FAILEDREAD(ktent); 452 } 453 454 if (doio(&kt, &enable, sizeof(enable), IO_WRITE)) 455 FAILEDWRITE(&kt); 456 } else { 457 if (doio(ktent, (u_char *)string, sizeof(string), IO_READ)) 458 FAILEDREAD(ktent); 459 if (doio(&kt, &enable, sizeof(enable), IO_READ)) 460 FAILEDREAD(&kt); 461 } 462 printf("%s=%s (%s)\n", ktent->kt_keyword, string, 463 enable == EE_TRUE ? "enabled" : "disabled"); 464 } 465 466 /* ARGSUSED */ 467 void 468 ee_notsupp(ktent, arg) 469 struct keytabent *ktent; 470 char *arg; 471 { 472 473 warnx("field `%s' not yet supported", ktent->kt_keyword); 474 } 475 476 static void 477 badval(ktent, arg) 478 struct keytabent *ktent; 479 char *arg; 480 { 481 482 warnx("inappropriate value `%s' for field `%s'", arg, 483 ktent->kt_keyword); 484 } 485 486 static int 487 doio(ktent, buf, len, wr) 488 struct keytabent *ktent; 489 u_char *buf; 490 ssize_t len; 491 int wr; 492 { 493 int fd, rval = 0; 494 u_char *buf2; 495 496 buf2 = (u_char *)calloc(1, len); 497 if (buf2 == NULL) { 498 memcpy(err_str, "memory allocation failed", sizeof err_str); 499 return (1); 500 } 501 502 fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640); 503 if (fd < 0) { 504 (void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom, 505 strerror(errno)); 506 free(buf2); 507 return (1); 508 } 509 510 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) { 511 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s", 512 path_eeprom, strerror(errno)); 513 rval = 1; 514 goto done; 515 } 516 517 if (read(fd, buf2, len) != len) { 518 (void)snprintf(err_str, sizeof err_str, "read: %s: %s", 519 path_eeprom, strerror(errno)); 520 return (1); 521 } 522 523 if (wr == IO_WRITE) { 524 if (memcmp(buf, buf2, len) == 0) 525 goto done; 526 527 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) { 528 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s", 529 path_eeprom, strerror(errno)); 530 rval = 1; 531 goto done; 532 } 533 534 ++update_checksums; 535 if (write(fd, buf, len) < 0) { 536 (void)snprintf(err_str, sizeof err_str, "write: %s: %s", 537 path_eeprom, strerror(errno)); 538 rval = 1; 539 goto done; 540 } 541 } else 542 memmove(buf, buf2, len); 543 544 done: 545 free(buf2); 546 (void)close(fd); 547 return (rval); 548 } 549 550 /* 551 * Read from eeLastHwUpdate to just before eeReserved. Calculate 552 * a checksum, and deposit 3 copies of it sequentially starting at 553 * eeChecksum[0]. Increment the write count, and deposit 3 copies 554 * of it sequentially starting at eeWriteCount[0]. 555 */ 556 void 557 ee_updatechecksums() 558 { 559 struct keytabent kt; 560 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC]; 561 u_char checksum; 562 int i; 563 564 kt.kt_keyword = "eeprom contents"; 565 kt.kt_offset = EE_HWUPDATE_LOC; 566 kt.kt_handler = ee_notsupp; 567 568 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) { 569 cksumfail = 1; 570 FAILEDREAD(&kt); 571 } 572 573 checksum = ee_checksum(checkme, sizeof(checkme)); 574 575 kt.kt_keyword = "eeprom checksum"; 576 for (i = 0; i < 4; ++i) { 577 kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum)); 578 if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) { 579 cksumfail = 1; 580 FAILEDWRITE(&kt); 581 } 582 } 583 584 kt.kt_keyword = "eeprom writecount"; 585 for (i = 0; i < 4; ++i) { 586 kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount)); 587 if (doio(&kt, (u_char *)&writecount, sizeof(writecount), 588 IO_WRITE)) { 589 cksumfail = 1; 590 FAILEDWRITE(&kt); 591 } 592 } 593 } 594 595 void 596 ee_verifychecksums() 597 { 598 struct keytabent kt; 599 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC]; 600 u_char checksum, ochecksum[3]; 601 u_short owritecount[3]; 602 603 /* 604 * Verify that the EEPROM's write counts match, and update the 605 * global copy for use later. 606 */ 607 kt.kt_keyword = "eeprom writecount"; 608 kt.kt_offset = EE_WC_LOC; 609 kt.kt_handler = ee_notsupp; 610 611 if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) { 612 cksumfail = 1; 613 FAILEDREAD(&kt); 614 } 615 616 if (owritecount[0] != owritecount[1] || 617 owritecount[0] != owritecount[2]) { 618 warnx("eeprom writecount mismatch %s", 619 ignore_checksum ? "(ignoring)" : 620 (fix_checksum ? "(fixing)" : "")); 621 622 if (!ignore_checksum && !fix_checksum) { 623 cksumfail = 1; 624 return; 625 } 626 627 writecount = MAXIMUM(owritecount[0], owritecount[1]); 628 writecount = MAXIMUM(writecount, owritecount[2]); 629 } else 630 writecount = owritecount[0]; 631 632 /* 633 * Verify that the EEPROM's checksums match and are correct. 634 */ 635 kt.kt_keyword = "eeprom checksum"; 636 kt.kt_offset = EE_CKSUM_LOC; 637 638 if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) { 639 cksumfail = 1; 640 FAILEDREAD(&kt); 641 } 642 643 if (ochecksum[0] != ochecksum[1] || 644 ochecksum[0] != ochecksum[2]) { 645 warnx("eeprom checksum mismatch %s", 646 ignore_checksum ? "(ignoring)" : 647 (fix_checksum ? "(fixing)" : "")); 648 649 if (!ignore_checksum && !fix_checksum) { 650 cksumfail = 1; 651 return; 652 } 653 } 654 655 kt.kt_keyword = "eeprom contents"; 656 kt.kt_offset = EE_HWUPDATE_LOC; 657 658 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) { 659 cksumfail = 1; 660 FAILEDREAD(&kt); 661 } 662 663 checksum = ee_checksum(checkme, sizeof(checkme)); 664 665 if (ochecksum[0] != checksum) { 666 warnx("eeprom checksum incorrect %s", 667 ignore_checksum ? "(ignoring)" : 668 (fix_checksum ? "(fixing)" : "")); 669 670 if (!ignore_checksum && !fix_checksum) { 671 cksumfail = 1; 672 return; 673 } 674 } 675 676 if (fix_checksum) 677 ee_updatechecksums(); 678 } 679 680 u_char 681 ee_checksum(area, len) 682 u_char *area; 683 size_t len; 684 { 685 u_char sum = 0; 686 687 while (len--) 688 sum += *area++; 689 690 return (0x100 - sum); 691 } 692