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