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