1 /*- 2 * Copyright (c) 1994-1996 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef lint 30 static const char rcsid[] = 31 "$FreeBSD$"; 32 #endif /* not lint */ 33 34 #include <ctype.h> 35 #include <err.h> 36 #include <limits.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <machine/console.h> 42 #include <sys/errno.h> 43 #include "path.h" 44 #include "decode.h" 45 46 char legal_colors[16][16] = { 47 "black", "blue", "green", "cyan", 48 "red", "magenta", "brown", "white", 49 "grey", "lightblue", "lightgreen", "lightcyan", 50 "lightred", "lightmagenta", "yellow", "lightwhite" 51 }; 52 int hex = 0; 53 int number; 54 char letter; 55 struct vid_info info; 56 57 58 static void 59 usage() 60 { 61 fprintf(stderr, "%s\n%s\n%s\n%s\n", 62 "usage: vidcontrol [-r fg bg] [-b color] [-c appearance] [-d] [-l scrmap]", 63 " [-i adapter | mode] [-L] [-M char] [-m on|off]", 64 " [-f size file] [-s number] [-t N|off] [-x] [mode]", 65 " [fgcol [bgcol]] [show]"); 66 exit(1); 67 } 68 69 char * 70 nextarg(int ac, char **av, int *indp, int oc) 71 { 72 if (*indp < ac) 73 return(av[(*indp)++]); 74 errx(1, "option requires two arguments -- %c", oc); 75 return(""); 76 } 77 78 char * 79 mkfullname(const char *s1, const char *s2, const char *s3) 80 { 81 static char *buf = NULL; 82 static int bufl = 0; 83 int f; 84 85 f = strlen(s1) + strlen(s2) + strlen(s3) + 1; 86 if (f > bufl) { 87 if (buf) 88 buf = (char *)realloc(buf, f); 89 else 90 buf = (char *)malloc(f); 91 } 92 if (!buf) { 93 bufl = 0; 94 return(NULL); 95 } 96 97 bufl = f; 98 strcpy(buf, s1); 99 strcat(buf, s2); 100 strcat(buf, s3); 101 return(buf); 102 } 103 104 void 105 load_scrnmap(char *filename) 106 { 107 FILE *fd = 0; 108 int i, size; 109 char *name; 110 scrmap_t scrnmap; 111 char *prefix[] = {"", "", SCRNMAP_PATH, SCRNMAP_PATH, NULL}; 112 char *postfix[] = {"", ".scm", "", ".scm"}; 113 114 for (i=0; prefix[i]; i++) { 115 name = mkfullname(prefix[i], filename, postfix[i]); 116 fd = fopen(name, "r"); 117 if (fd) 118 break; 119 } 120 if (fd == NULL) { 121 warn("screenmap file not found"); 122 return; 123 } 124 size = sizeof(scrnmap); 125 if (decode(fd, (char *)&scrnmap) != size) { 126 rewind(fd); 127 if (fread(&scrnmap, 1, size, fd) != size) { 128 warnx("bad screenmap file"); 129 fclose(fd); 130 return; 131 } 132 } 133 if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0) 134 warn("can't load screenmap"); 135 fclose(fd); 136 } 137 138 void 139 load_default_scrnmap() 140 { 141 scrmap_t scrnmap; 142 int i; 143 144 for (i=0; i<256; i++) 145 *((char*)&scrnmap + i) = i; 146 if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0) 147 warn("can't load default screenmap"); 148 } 149 150 void 151 print_scrnmap() 152 { 153 unsigned char map[256]; 154 int i; 155 156 if (ioctl(0, GIO_SCRNMAP, &map) < 0) { 157 warn("getting screenmap"); 158 return; 159 } 160 for (i=0; i<sizeof(map); i++) { 161 if (i > 0 && i % 16 == 0) 162 fprintf(stdout, "\n"); 163 if (hex) 164 fprintf(stdout, " %02x", map[i]); 165 else 166 fprintf(stdout, " %03d", map[i]); 167 } 168 fprintf(stdout, "\n"); 169 170 } 171 172 void 173 load_font(char *type, char *filename) 174 { 175 FILE *fd = 0; 176 int i, size; 177 unsigned long io; 178 char *name, *fontmap; 179 char *prefix[] = {"", "", FONT_PATH, FONT_PATH, NULL}; 180 char *postfix[] = {"", ".fnt", "", ".fnt"}; 181 182 for (i=0; prefix[i]; i++) { 183 name = mkfullname(prefix[i], filename, postfix[i]); 184 fd = fopen(name, "r"); 185 if (fd) 186 break; 187 } 188 if (fd == NULL) { 189 warn("font file not found"); 190 return; 191 } 192 if (!strcmp(type, "8x8")) { 193 size = 8*256; 194 io = PIO_FONT8x8; 195 } 196 else if (!strcmp(type, "8x14")) { 197 size = 14*256; 198 io = PIO_FONT8x14; 199 } 200 else if (!strcmp(type, "8x16")) { 201 size = 16*256; 202 io = PIO_FONT8x16; 203 } 204 else { 205 warn("bad font size specification"); 206 fclose(fd); 207 return; 208 } 209 fontmap = (char*) malloc(size); 210 if (decode(fd, fontmap) != size) { 211 rewind(fd); 212 if (fread(fontmap, 1, size, fd) != size) { 213 warnx("bad font file"); 214 fclose(fd); 215 free(fontmap); 216 return; 217 } 218 } 219 if (ioctl(0, io, fontmap) < 0) 220 warn("can't load font"); 221 fclose(fd); 222 free(fontmap); 223 } 224 225 void 226 set_screensaver_timeout(char *arg) 227 { 228 int nsec; 229 230 if (!strcmp(arg, "off")) 231 nsec = 0; 232 else { 233 nsec = atoi(arg); 234 if ((*arg == '\0') || (nsec < 1)) { 235 warnx("argument must be a positive number"); 236 return; 237 } 238 } 239 if (ioctl(0, CONS_BLANKTIME, &nsec) == -1) 240 warn("setting screensaver period"); 241 } 242 243 void 244 set_cursor_type(char *appearence) 245 { 246 int type; 247 248 if (!strcmp(appearence, "normal")) 249 type = 0; 250 else if (!strcmp(appearence, "blink")) 251 type = 1; 252 else if (!strcmp(appearence, "destructive")) 253 type = 3; 254 else { 255 warnx("argument to -c must be normal, blink or destructive"); 256 return; 257 } 258 ioctl(0, CONS_CURSORTYPE, &type); 259 } 260 261 void 262 video_mode(int argc, char **argv, int *index) 263 { 264 static struct { 265 char *name; 266 unsigned long mode; 267 } modes[] = { 268 { "80x25", SW_TEXT_80x25 }, 269 { "80x30", SW_TEXT_80x30 }, 270 { "80x43", SW_TEXT_80x43 }, 271 { "80x50", SW_TEXT_80x50 }, 272 { "80x60", SW_TEXT_80x60 }, 273 { "132x25", SW_TEXT_132x25 }, 274 { "132x30", SW_TEXT_132x30 }, 275 { "132x43", SW_TEXT_132x43 }, 276 { "132x50", SW_TEXT_132x50 }, 277 { "132x60", SW_TEXT_132x60 }, 278 { "VGA_40x25", SW_VGA_C40x25 }, 279 { "VGA_80x25", SW_VGA_C80x25 }, 280 { "VGA_80x30", SW_VGA_C80x30 }, 281 { "VGA_80x50", SW_VGA_C80x50 }, 282 { "VGA_80x60", SW_VGA_C80x60 }, 283 #ifdef SW_VGA_C90x25 284 { "VGA_90x25", SW_VGA_C90x25 }, 285 { "VGA_90x30", SW_VGA_C90x30 }, 286 { "VGA_90x43", SW_VGA_C90x43 }, 287 { "VGA_90x50", SW_VGA_C90x50 }, 288 { "VGA_90x60", SW_VGA_C90x60 }, 289 #endif 290 { "VGA_320x200", SW_VGA_CG320 }, 291 { "EGA_80x25", SW_ENH_C80x25 }, 292 { "EGA_80x43", SW_ENH_C80x43 }, 293 { "VESA_132x25", SW_VESA_C132x25 }, 294 { "VESA_132x43", SW_VESA_C132x43 }, 295 { "VESA_132x50", SW_VESA_C132x50 }, 296 { "VESA_132x60", SW_VESA_C132x60 }, 297 { "VESA_800x600", SW_VESA_800x600 }, 298 { NULL }, 299 }; 300 unsigned long mode = 0; 301 int cur_mode; 302 int ioerr; 303 int size[3]; 304 int i; 305 306 if (ioctl(0, CONS_GET, &cur_mode) < 0) 307 err(1, "cannot get the current video mode"); 308 if (*index < argc) { 309 for (i = 0; modes[i].name != NULL; ++i) { 310 if (!strcmp(argv[*index], modes[i].name)) { 311 mode = modes[i].mode; 312 break; 313 } 314 } 315 if (modes[i].name == NULL) 316 return; 317 if (ioctl(0, mode, NULL) < 0) 318 warn("cannot set videomode"); 319 if (mode == SW_VESA_800x600) { 320 size[0] = 80; /* columns */ 321 size[1] = 25; /* rows */ 322 size[2] = 16; /* font size */ 323 if (ioctl(0, KDRASTER, size)) { 324 ioerr = errno; 325 if (cur_mode >= M_VESA_BASE) 326 ioctl(0, _IO('V', cur_mode), NULL); 327 else 328 ioctl(0, _IO('S', cur_mode), NULL); 329 warnc(ioerr, "cannot activate raster display"); 330 } 331 } 332 (*index)++; 333 } 334 return; 335 } 336 337 int 338 get_color_number(char *color) 339 { 340 int i; 341 342 for (i=0; i<16; i++) 343 if (!strcmp(color, legal_colors[i])) 344 return i; 345 return -1; 346 } 347 348 void 349 set_normal_colors(int argc, char **argv, int *index) 350 { 351 int color; 352 353 if (*index < argc && (color = get_color_number(argv[*index])) != -1) { 354 (*index)++; 355 fprintf(stderr, "[=%dF", color); 356 if (*index < argc 357 && (color = get_color_number(argv[*index])) != -1 358 && color < 8) { 359 (*index)++; 360 fprintf(stderr, "[=%dG", color); 361 } 362 } 363 } 364 365 void 366 set_reverse_colors(int argc, char **argv, int *index) 367 { 368 int color; 369 370 if ((color = get_color_number(argv[*(index)-1])) != -1) { 371 fprintf(stderr, "[=%dH", color); 372 if (*index < argc 373 && (color = get_color_number(argv[*index])) != -1 374 && color < 8) { 375 (*index)++; 376 fprintf(stderr, "[=%dI", color); 377 } 378 } 379 } 380 381 void 382 set_console(char *arg) 383 { 384 int n; 385 386 if( !arg || strspn(arg,"0123456789") != strlen(arg)) { 387 warnx("bad console number"); 388 return; 389 } 390 391 n = atoi(arg); 392 if (n < 1 || n > 16) { 393 warnx("console number out of range"); 394 } else if (ioctl(0, VT_ACTIVATE, (caddr_t) (long) n) == -1) 395 warn("ioctl(VT_ACTIVATE)"); 396 } 397 398 void 399 set_border_color(char *arg) 400 { 401 int color; 402 403 if ((color = get_color_number(arg)) != -1) { 404 fprintf(stderr, "[=%dA", color); 405 } 406 else 407 usage(); 408 } 409 410 void 411 set_mouse_char(char *arg) 412 { 413 struct mouse_info mouse; 414 long l; 415 416 l = strtol(arg, NULL, 0); 417 if ((l < 0) || (l > UCHAR_MAX)) { 418 warnx("argument to -M must be 0 through %d", UCHAR_MAX); 419 return; 420 } 421 mouse.operation = MOUSE_MOUSECHAR; 422 mouse.u.mouse_char = (int)l; 423 ioctl(0, CONS_MOUSECTL, &mouse); 424 } 425 426 void 427 set_mouse(char *arg) 428 { 429 struct mouse_info mouse; 430 431 if (!strcmp(arg, "on")) 432 mouse.operation = MOUSE_SHOW; 433 else if (!strcmp(arg, "off")) 434 mouse.operation = MOUSE_HIDE; 435 else { 436 warnx("argument to -m must either on or off"); 437 return; 438 } 439 ioctl(0, CONS_MOUSECTL, &mouse); 440 } 441 442 static char 443 *adapter_name(int type) 444 { 445 static struct { 446 int type; 447 char *name; 448 } names[] = { 449 { KD_MONO, "MDA" }, 450 { KD_HERCULES, "Hercules" }, 451 { KD_CGA, "CGA" }, 452 { KD_EGA, "EGA" }, 453 { KD_VGA, "VGA" }, 454 { KD_PC98, "PC-98xx" }, 455 { KD_TGA, "TGA" }, 456 { -1, "Unknown" }, 457 }; 458 int i; 459 460 for (i = 0; names[i].type != -1; ++i) 461 if (names[i].type == type) 462 break; 463 return names[i].name; 464 } 465 466 void 467 show_adapter_info(void) 468 { 469 struct video_adapter_info ad; 470 471 ad.va_index = 0; 472 if (ioctl(0, CONS_ADPINFO, &ad)) { 473 warn("failed to obtain adapter information"); 474 return; 475 } 476 477 printf("fb%d:\n", ad.va_index); 478 printf(" %.*s%d, type:%s%s (%d), flags:0x%x\n", 479 (int)sizeof(ad.va_name), ad.va_name, ad.va_unit, 480 (ad.va_flags & V_ADP_VESA) ? "VESA " : "", 481 adapter_name(ad.va_type), ad.va_type, ad.va_flags); 482 printf(" initial mode:%d, current mode:%d, BIOS mode:%d\n", 483 ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode); 484 printf(" frame buffer window:0x%x, buffer size:0x%x\n", 485 ad.va_window, ad.va_buffer_size); 486 printf(" window size:0x%x, origin:0x%x\n", 487 ad.va_window_size, ad.va_window_orig); 488 printf(" display start address (%d, %d), scan line width:%d\n", 489 ad.va_disp_start.x, ad.va_disp_start.y, ad.va_line_width); 490 printf(" reserved:0x%x\n", ad.va_unused0); 491 } 492 493 void 494 show_mode_info(void) 495 { 496 struct video_info info; 497 char buf[80]; 498 int mode; 499 int c; 500 501 printf(" mode# flags type size " 502 "font window linear buffer\n"); 503 printf("---------------------------------------" 504 "---------------------------------------\n"); 505 for (mode = 0; mode < M_VESA_MODE_MAX; ++mode) { 506 info.vi_mode = mode; 507 if (ioctl(0, CONS_MODEINFO, &info)) 508 continue; 509 if (info.vi_mode != mode) 510 continue; 511 512 printf("%3d (0x%03x)", mode, mode); 513 printf(" 0x%08x", info.vi_flags); 514 if (info.vi_flags & V_INFO_GRAPHICS) { 515 c = 'G'; 516 snprintf(buf, sizeof(buf), "%dx%dx%d %d", 517 info.vi_width, info.vi_height, 518 info.vi_depth, info.vi_planes); 519 } else { 520 c = 'T'; 521 snprintf(buf, sizeof(buf), "%dx%d", 522 info.vi_width, info.vi_height); 523 } 524 printf(" %c %-15s", c, buf); 525 snprintf(buf, sizeof(buf), "%dx%d", 526 info.vi_cwidth, info.vi_cheight); 527 printf(" %-5s", buf); 528 printf(" 0x%05x %2dk %2dk", 529 info.vi_window, (int)info.vi_window_size/1024, 530 (int)info.vi_window_gran/1024); 531 printf(" 0x%08x %dk\n", 532 info.vi_buffer, (int)info.vi_buffer_size/1024); 533 } 534 } 535 536 void 537 show_info(char *arg) 538 { 539 if (!strcmp(arg, "adapter")) 540 show_adapter_info(); 541 else if (!strcmp(arg, "mode")) 542 show_mode_info(); 543 else { 544 warnx("argument to -i must either adapter or mode"); 545 return; 546 } 547 } 548 549 void 550 test_frame() 551 { 552 int i; 553 554 fprintf(stdout, "[=0G\n\n"); 555 for (i=0; i<8; i++) { 556 fprintf(stdout, "[=15F[=0G %2d [=%dF%-16s" 557 "[=15F[=0G %2d [=%dF%-16s " 558 "[=15F %2d [=%dGBACKGROUND[=0G\n", 559 i, i, legal_colors[i], i+8, i+8, 560 legal_colors[i+8], i, i); 561 } 562 fprintf(stdout, "[=%dF[=%dG[=%dH[=%dI\n", 563 info.mv_norm.fore, info.mv_norm.back, 564 info.mv_rev.fore, info.mv_rev.back); 565 } 566 567 int 568 main(int argc, char **argv) 569 { 570 int opt; 571 572 573 info.size = sizeof(info); 574 if (ioctl(0, CONS_GETINFO, &info) < 0) 575 err(1, "must be on a virtual console"); 576 while((opt = getopt(argc, argv, "b:c:df:i:l:LM:m:r:s:t:x")) != -1) 577 switch(opt) { 578 case 'b': 579 set_border_color(optarg); 580 break; 581 case 'c': 582 set_cursor_type(optarg); 583 break; 584 case 'd': 585 print_scrnmap(); 586 break; 587 case 'f': 588 load_font(optarg, 589 nextarg(argc, argv, &optind, 'f')); 590 break; 591 case 'i': 592 show_info(optarg); 593 break; 594 case 'l': 595 load_scrnmap(optarg); 596 break; 597 case 'L': 598 load_default_scrnmap(); 599 break; 600 case 'M': 601 set_mouse_char(optarg); 602 break; 603 case 'm': 604 set_mouse(optarg); 605 break; 606 case 'r': 607 set_reverse_colors(argc, argv, &optind); 608 break; 609 case 's': 610 set_console(optarg); 611 break; 612 case 't': 613 set_screensaver_timeout(optarg); 614 break; 615 case 'x': 616 hex = 1; 617 break; 618 default: 619 usage(); 620 } 621 video_mode(argc, argv, &optind); 622 set_normal_colors(argc, argv, &optind); 623 if (optind < argc && !strcmp(argv[optind], "show")) { 624 test_frame(); 625 optind++; 626 } 627 if ((optind != argc) || (argc == 1)) 628 usage(); 629 return 0; 630 } 631 632