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