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