eehandlers.c revision 1.6 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