1 /* $NetBSD: methods.c,v 1.8 2018/01/23 21:06:25 sevan Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Minoura Makoto. 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 * 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. 30 */ 31 32 #include <stdio.h> 33 #include <string.h> 34 #include <err.h> 35 #include <sys/types.h> 36 37 #include "memswitch.h" 38 #include "methods.h" 39 40 int 41 atoi_(const char **p) 42 { 43 const char *p1 = *p; 44 int v = 0; 45 int first = 1; 46 47 while (*p1 == ' ' || *p1 == '\t') 48 p1++; 49 50 if (*p1 == 0) { 51 *p = 0; 52 return 0; 53 } 54 if (strlen(p1) >= 2 && strncasecmp("0x", p1, 2) == 0) { 55 p1 += 2; 56 while (1) { 57 if (*p1 >= '0' && *p1 <= '9') { 58 v *= 16; 59 v += *p1 - '0'; 60 first = 0; 61 } else if (*p1 >= 'A' && *p1 <= 'F') { 62 v *= 16; 63 v += *p1 - 'A' + 10; 64 first = 0; 65 } else if (*p1 >= 'a' && *p1 <= 'f') { 66 v *= 16; 67 v += *p1 - 'a' + 10; 68 first = 0; 69 } else { 70 break; 71 } 72 p1++; 73 } 74 } else { 75 while (1) { 76 if (*p1 >= '0' && *p1 <= '9') { 77 v *= 10; 78 v += *p1 - '0'; 79 first = 0; 80 } else { 81 break; 82 } 83 p1++; 84 } 85 } 86 87 if (first) { 88 *p = 0; 89 return 0; 90 } 91 92 while (*p1 == ' ' || *p1 == '\t') p1++; 93 *p = p1; 94 return v; 95 } 96 97 int 98 fill_uchar(struct property *prop) 99 { 100 if (current_values == 0) 101 alloc_current_values(); 102 103 prop->current_value.byte[0] = current_values[prop->offset]; 104 prop->current_value.byte[1] = 0; 105 prop->current_value.byte[2] = 0; 106 prop->current_value.byte[3] = 0; 107 prop->value_valid = 1; 108 109 return 0; 110 } 111 112 int 113 fill_ushort(struct property *prop) 114 { 115 if (current_values == 0) 116 alloc_current_values(); 117 118 prop->current_value.byte[0] = current_values[prop->offset]; 119 prop->current_value.byte[1] = current_values[prop->offset+1]; 120 prop->current_value.byte[2] = 0; 121 prop->current_value.byte[3] = 0; 122 prop->value_valid = 1; 123 124 return 0; 125 } 126 127 int 128 fill_ulong(struct property *prop) 129 { 130 if (current_values == 0) 131 alloc_current_values(); 132 133 prop->current_value.byte[0] = current_values[prop->offset]; 134 prop->current_value.byte[1] = current_values[prop->offset+1]; 135 prop->current_value.byte[2] = current_values[prop->offset+2]; 136 prop->current_value.byte[3] = current_values[prop->offset+3]; 137 prop->value_valid = 1; 138 139 return 0; 140 } 141 142 int 143 flush_uchar(struct property *prop) 144 { 145 if (!prop->modified) 146 return 0; 147 148 if (modified_values == 0) 149 alloc_modified_values(); 150 151 modified_values[prop->offset] = prop->modified_value.byte[0]; 152 153 return 0; 154 } 155 156 int 157 flush_ushort(struct property *prop) 158 { 159 if (!prop->modified) 160 return 0; 161 162 if (modified_values == 0) 163 alloc_modified_values(); 164 165 modified_values[prop->offset] = prop->modified_value.byte[0]; 166 modified_values[prop->offset+1] = prop->modified_value.byte[1]; 167 168 return 0; 169 } 170 171 int 172 flush_ulong(struct property *prop) 173 { 174 if (!prop->modified) 175 return 0; 176 177 if (modified_values == 0) 178 alloc_modified_values(); 179 180 modified_values[prop->offset] = prop->modified_value.byte[0]; 181 modified_values[prop->offset+1] = prop->modified_value.byte[1]; 182 modified_values[prop->offset+2] = prop->modified_value.byte[2]; 183 modified_values[prop->offset+3] = prop->modified_value.byte[3]; 184 185 return 0; 186 } 187 188 int 189 flush_dummy(struct property *prop) 190 { 191 return 0; 192 } 193 194 int 195 parse_dummy(struct property *prop, const char *value) 196 { 197 warnx("Cannot modify %s.%s", prop->class, prop->node); 198 199 return -1; 200 } 201 202 int 203 parse_byte(struct property *prop, const char *value) 204 { 205 const char *p = value; 206 int v; 207 208 v = atoi_(&p); 209 if (p == 0) { 210 warnx("%s: Invalid value", value); 211 return -1; 212 } 213 214 if (strcasecmp("MB", p) == 0) 215 v *= 1024 * 1024; 216 else if (strcasecmp("KB", p) == 0) 217 v *= 1024; 218 else if (*p != 0 && 219 strcasecmp("B", p) != 0) { 220 warnx("%s: Invalid value", value); 221 return -1; 222 } 223 224 if (v < prop->min) { 225 warnx("%s: Too small", value); 226 return -1; 227 } else if (v > prop->max) { 228 warnx("%s: Too large", value); 229 return -1; 230 } 231 232 prop->modified = 1; 233 prop->modified_value.longword = v; 234 235 return 0; 236 } 237 238 int 239 parse_uchar(struct property *prop, const char *value) 240 { 241 const char *p = value; 242 int v; 243 244 v = atoi_(&p); 245 if (p == 0) { 246 warnx("%s: Invalid value", value); 247 return -1; 248 } 249 250 if (v < prop->min) { 251 warnx("%s: Too small", value); 252 return -1; 253 } else if (v > prop->max) { 254 warnx("%s: Too large", value); 255 return -1; 256 } 257 258 prop->modified = 1; 259 prop->modified_value.byte[0] = v; 260 261 return 0; 262 } 263 264 int 265 parse_ulong(struct property *prop, const char *value) 266 { 267 const char *p = value; 268 int v; 269 270 v = atoi_(&p); 271 if (p == 0) { 272 warnx("%s: Invalid value", value); 273 return -1; 274 } 275 276 if (v < prop->min) { 277 warnx("%s: Too small", value); 278 return -1; 279 } else if (v > prop->max) { 280 warnx("%s: Too large", value); 281 return -1; 282 } 283 284 prop->modified = 1; 285 prop->modified_value.longword = v; 286 287 return 0; 288 } 289 290 int 291 parse_ushort(struct property *prop, const char *value) 292 { 293 const char *p = value; 294 int v; 295 296 v = atoi_(&p); 297 if (p == 0) { 298 warnx("%s: Invalid value", value); 299 return -1; 300 } 301 302 if (v < prop->min) { 303 warnx("%s: Too small", value); 304 return -1; 305 } else if (v > prop->max) { 306 warnx("%s: Too large", value); 307 return -1; 308 } 309 310 prop->modified = 1; 311 prop->modified_value.word[0] = v; 312 313 return 0; 314 } 315 316 int 317 parse_time(struct property *prop, const char *value) 318 { 319 const char *p = value; 320 int v; 321 322 while (*p == ' ' || *p == '\t') p++; 323 if (*p == '-') { 324 p++; 325 v = -atoi_(&p); 326 } else 327 v = atoi_(&p); 328 if (p == 0) { 329 warnx("%s: Invalid value", value); 330 return -1; 331 } 332 333 if (strcasecmp("hours", p) == 0 || strcasecmp("hour", p) == 0) 334 v *= 60 * 60; 335 else if (strcasecmp("minutes", p) == 0 || 336 strcasecmp("minute", p) == 0) 337 v *= 60; 338 else if (*p != 0 && 339 strcasecmp("second", p) != 0 && 340 strcasecmp("seconds", p) != 0) { 341 warnx("%s: Invalid value", value); 342 return -1; 343 } 344 345 if (v < prop->min) { 346 warnx("%s: Too small", value); 347 return -1; 348 } else if (v > prop->max) { 349 warnx("%s: Too large", value); 350 return -1; 351 } 352 353 prop->modified = 1; 354 prop->modified_value.longword = v; 355 356 return 0; 357 } 358 359 int 360 parse_bootdev(struct property *prop, const char *value) 361 { 362 const char *p = value; 363 int v; 364 char expr_scsi[32]; 365 366 while (*p == ' ' || *p == '\t') p++; 367 368 if (strcasecmp("STD", p) == 0) 369 v = 0; 370 else if (strcasecmp("ROM", p) == 0) 371 v = 0xa000; 372 else if (strcasecmp("RAM", p) == 0) 373 v = 0xb000; 374 else if (strncasecmp("HD", p, 2) == 0) { 375 p += 2; 376 v = atoi_(&p); 377 if (p == 0 || v < 0 || v > 15) { 378 warnx("%s: Invalid value", value); 379 return -1; 380 } 381 v *= 0x0100; 382 v += 0x8000; 383 } else if (strncasecmp("FD", p, 2) == 0) { 384 p += 2; 385 v = atoi_(&p); 386 if (p == 0 || v < 0 || v > 3) { 387 warnx("%s: Invalid value", value); 388 return -1; 389 } 390 v *= 0x0100; 391 v += 0x9070; 392 } else if (strncasecmp("INSCSI", p, 6) == 0 || 393 strncasecmp("EXSCSI", p, 6) == 0) { 394 int isin = strncasecmp("EXSCSI", p, 6); 395 396 p += 6; 397 v = atoi_(&p); 398 if (p == 0 || v < 0 || v > 7) { 399 warnx("%s: Invalid value", value); 400 return -1; 401 } 402 403 /* change boot.romaddr */ 404 sprintf(expr_scsi, "boot.romaddr=0x%06x", 405 (isin ? 0xfc0000 : 0xea0020) + v * 4); 406 modify_single(expr_scsi); 407 408 /* boot.device again */ 409 v = 0xa000; 410 } else { 411 warnx("%s: Invalid value", value); 412 return -1; 413 } 414 415 prop->modified = 1; 416 prop->modified_value.word[0] = v; 417 418 return 0; 419 } 420 421 int 422 parse_serial(struct property *prop, const char *value) 423 #define NEXTSPEC while (*p == ' ' || *p == '\t') p++; \ 424 if (*p++ != ',') { \ 425 warnx("%s: Invalid value", value); \ 426 return -1; \ 427 } \ 428 while (*p == ' ' || *p == '\t') p++; 429 { 430 const char *p = value; 431 const char *q; 432 int baud, bit, parity, stop, flow; 433 static const int bauds[] = {75, 150, 300, 600, 1200, 2400, 4800, 9600, 434 17361, 0}; 435 static const char parities[] = "noe"; 436 int i; 437 438 while (*p == ' ' || *p == '\t') p++; 439 440 /* speed */ 441 baud = atoi_(&p); 442 if (p == 0) { 443 warnx("%s: Invalid value", value); 444 return -1; 445 } 446 for (i = 0; bauds[i]; i++) 447 if (baud == bauds[i]) 448 break; 449 if (bauds[i] == 0) { 450 warnx("%d: Invalid speed", baud); 451 return -1; 452 } 453 baud = i; 454 455 NEXTSPEC; 456 457 /* bit size */ 458 if (*p < '5' || *p > '8') { 459 warnx("%c: Invalid bit size", *p); 460 return -1; 461 } 462 bit = *p++ - '5'; 463 464 NEXTSPEC; 465 466 /* parity */ 467 q = strchr(parities, *p++); 468 if (q == 0) { 469 warnx("%c: Invalid parity spec", *p); 470 return -1; 471 } 472 parity = q - parities; 473 474 NEXTSPEC; 475 476 /* stop bit */ 477 if (strncmp(p, "1.5", 3) == 0) { 478 stop = 2; 479 p += 3; 480 } else if (strncmp(p, "2", 1) == 0) { 481 stop = 0; 482 p++; 483 } else if (strncmp(p, "1", 1) == 0) { 484 stop = 1; 485 p++; 486 } else { 487 warnx("%s: Invalid value", value); 488 return -1; 489 } 490 491 NEXTSPEC; 492 493 /* flow */ 494 if (*p == '-') 495 flow = 0; 496 else if (*p == 's') 497 flow = 1; 498 else { 499 warnx("%s: Invalid value", value); 500 return -1; 501 } 502 503 p++; 504 while (*p == ' ' || *p == '\t') p++; 505 if (*p != 0) { 506 warnx("%s: Invalid value", value); 507 return -1; 508 } 509 510 prop->modified = 1; 511 prop->modified_value.word[0] = ((stop << 14) + 512 (parity << 12) + 513 (bit << 10) + 514 (flow << 9) + 515 baud); 516 517 return 0; 518 } 519 #undef NEXTSPEC 520 521 int 522 parse_srammode(struct property *prop, const char *value) 523 { 524 static const char *const sramstrs[] = {"unused", "SRAMDISK", "program"}; 525 int i; 526 527 for (i = 0; i <= 2; i++) { 528 if (strcasecmp(value, sramstrs[i]) == 0) 529 break; 530 } 531 if (i > 2) { 532 warnx("%s: Invalid value", value); 533 return -1; 534 } 535 536 prop->modified = 1; 537 prop->modified_value.byte[0] = i; 538 539 return 0; 540 } 541 542 int 543 print_uchar(struct property *prop, char *str) 544 { 545 if (prop->modified) 546 snprintf(str, MAXVALUELEN, 547 "%d", prop->modified_value.byte[0]); 548 else { 549 if (!prop->value_valid) 550 prop->fill(prop); 551 snprintf(str, MAXVALUELEN, "%d", 552 prop->current_value.byte[0]); 553 } 554 555 return 0; 556 } 557 558 int 559 print_ucharh(struct property *prop, char *str) 560 { 561 if (prop->modified) 562 snprintf(str, MAXVALUELEN, 563 "0x%4.4x", prop->modified_value.byte[0]); 564 else { 565 if (!prop->value_valid) 566 prop->fill(prop); 567 snprintf(str, MAXVALUELEN, 568 "0x%4.4x", prop->current_value.byte[0]); 569 } 570 571 return 0; 572 } 573 574 int 575 print_ushorth(struct property *prop, char *str) 576 { 577 if (prop->modified) 578 snprintf(str, MAXVALUELEN, 579 "0x%4.4x", prop->modified_value.word[0]); 580 else { 581 if (!prop->value_valid) 582 prop->fill(prop); 583 snprintf(str, MAXVALUELEN, 584 "0x%4.4x", prop->current_value.word[0]); 585 } 586 587 return 0; 588 } 589 590 int 591 print_ulong(struct property *prop, char *str) 592 { 593 if (prop->modified) 594 snprintf(str, MAXVALUELEN, 595 "%ld", prop->modified_value.longword); 596 else { 597 if (!prop->value_valid) 598 prop->fill(prop); 599 snprintf(str, MAXVALUELEN, 600 "%ld", prop->current_value.longword); 601 } 602 603 return 0; 604 } 605 606 int 607 print_ulongh(struct property *prop, char *str) 608 { 609 if (prop->modified) 610 snprintf(str, MAXVALUELEN, 611 "0x%8.8lx", prop->modified_value.longword); 612 else { 613 if (!prop->value_valid) 614 prop->fill(prop); 615 snprintf(str, MAXVALUELEN, 616 "0x%8.8lx", prop->current_value.longword); 617 } 618 619 return 0; 620 } 621 622 int 623 print_magic(struct property *prop, char *str) 624 { 625 if (!prop->value_valid) 626 prop->fill(prop); 627 snprintf(str, MAXVALUELEN, "%c%c%c%c", 628 prop->current_value.byte[0], 629 prop->current_value.byte[1], 630 prop->current_value.byte[2], 631 prop->current_value.byte[3]); 632 633 return 0; 634 } 635 636 int 637 print_timesec(struct property *prop, char *str) 638 { 639 if (prop->modified) 640 snprintf(str, MAXVALUELEN, 641 "%ld second", prop->modified_value.longword); 642 else { 643 if (!prop->value_valid) 644 prop->fill(prop); 645 snprintf(str, MAXVALUELEN, 646 "%ld second", prop->current_value.longword); 647 } 648 649 return 0; 650 } 651 652 int 653 print_bootdev(struct property *prop, char *str) 654 { 655 unsigned int v; 656 657 if (prop->modified) 658 v = prop->modified_value.word[0]; 659 else { 660 if (!prop->value_valid) 661 prop->fill(prop); 662 v = prop->current_value.word[0]; 663 } 664 665 if (v == 0) 666 strcpy(str, "STD"); 667 else if (v == 0xa000) 668 strcpy(str, "ROM"); 669 else if (v == 0xb000) 670 strcpy(str, "RAM"); 671 else if (v >= 0x8000 && v < 0x9000) 672 snprintf(str, MAXVALUELEN, "HD%d", (v & 0x0f00) >> 8); 673 else if (v >= 0x9000 && v < 0xa000) 674 snprintf(str, MAXVALUELEN, "FD%d", (v & 0x0f00) >> 8); 675 else 676 snprintf(str, MAXVALUELEN, "%8.8x", v); 677 678 return 0; 679 } 680 681 int 682 print_serial(struct property *prop, char *str) 683 { 684 unsigned int v; 685 const char *baud, *stop; 686 char bit, parity, flow; 687 static const char *const bauds[] = {"75", "150", "300", "600", "1200", 688 "2400", "4800", "9600", "17361"}; 689 static const char bits[] = "5678"; 690 static const char parities[] = "noen"; 691 static const char *const stops[] = {"2", "1", "1.5", "2"}; 692 static const char flows[] = "-s"; 693 694 if (prop->modified) 695 v = prop->modified_value.word[0]; 696 else { 697 if (!prop->value_valid) 698 prop->fill(prop); 699 v = prop->current_value.word[0]; 700 } 701 702 baud = bauds[v & 0x000f]; 703 bit = bits[(v & 0x0c00) >> 10]; 704 parity = parities[(v & 0x3000) >> 12]; 705 stop = stops[(v & 0xe000) >> 14]; 706 flow = flows[(v & 0x0200) >> 9]; 707 sprintf(str, "%s,%c,%c,%s,%c", baud, bit, parity, stop, flow); 708 709 return 0; 710 } 711 712 int 713 print_srammode(struct property *prop, char *str) 714 { 715 int v; 716 static const char *const sramstrs[] = {"unused", "SRAMDISK", "program"}; 717 718 if (prop->modified) 719 v = prop->modified_value.byte[0]; 720 else { 721 if (!prop->value_valid) 722 prop->fill(prop); 723 v = prop->current_value.byte[0]; 724 } 725 726 if (v < 0 || v > 2) 727 strcpy(str, "INVALID"); 728 else 729 strcpy(str, sramstrs[v]); 730 731 return 0; 732 } 733