vidcontrol.c revision 39592
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 "$Id: vidcontrol.c,v 1.21 1998/09/16 13:55:26 abial Exp $"; 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 { "VGA_320x200", SW_VGA_CG320 }, 281 { "EGA_80x25", SW_ENH_C80x25 }, 282 { "EGA_80x43", SW_ENH_C80x43 }, 283 { "VESA_132x25", SW_VESA_C132x25 }, 284 { "VESA_132x43", SW_VESA_C132x43 }, 285 { "VESA_132x50", SW_VESA_C132x50 }, 286 { "VESA_132x60", SW_VESA_C132x60 }, 287 { "VESA_800x600", SW_VESA_800x600 }, 288 { NULL }, 289 }; 290 unsigned long mode; 291 int size[3]; 292 int i; 293 294 if (*index < argc) { 295 for (i = 0; modes[i].name != NULL; ++i) { 296 if (!strcmp(argv[*index], modes[i].name)) { 297 mode = modes[i].mode; 298 break; 299 } 300 } 301 if (modes[i].name == NULL) 302 return; 303 if (ioctl(0, mode, NULL) < 0) 304 warn("cannot set videomode"); 305 if (mode == SW_VESA_800x600) { 306 size[0] = 80; /* columns */ 307 size[1] = 25; /* rows */ 308 size[2] = 16; /* font size */ 309 if (ioctl(0, KDRASTER, size)) 310 warn("cannot activate raster display"); 311 } 312 (*index)++; 313 } 314 return; 315} 316 317int 318get_color_number(char *color) 319{ 320 int i; 321 322 for (i=0; i<16; i++) 323 if (!strcmp(color, legal_colors[i])) 324 return i; 325 return -1; 326} 327 328void 329set_normal_colors(int argc, char **argv, int *index) 330{ 331 int color; 332 333 if (*index < argc && (color = get_color_number(argv[*index])) != -1) { 334 (*index)++; 335 fprintf(stderr, "[=%dF", color); 336 if (*index < argc 337 && (color = get_color_number(argv[*index])) != -1 338 && color < 8) { 339 (*index)++; 340 fprintf(stderr, "[=%dG", color); 341 } 342 } 343} 344 345void 346set_reverse_colors(int argc, char **argv, int *index) 347{ 348 int color; 349 350 if ((color = get_color_number(argv[*(index)-1])) != -1) { 351 fprintf(stderr, "[=%dH", color); 352 if (*index < argc 353 && (color = get_color_number(argv[*index])) != -1 354 && color < 8) { 355 (*index)++; 356 fprintf(stderr, "[=%dI", color); 357 } 358 } 359} 360 361void 362set_console(char *arg) 363{ 364 int n; 365 366 if( !arg || strspn(arg,"0123456789") != strlen(arg)) { 367 warnx("bad console number"); 368 return; 369 } 370 371 n = atoi(arg); 372 if (n < 1 || n > 12) { 373 warnx("console number out of range"); 374 } else if (ioctl(0,VT_ACTIVATE,(char *)n) == -1) 375 warn("ioctl(VT_ACTIVATE)"); 376} 377 378void 379set_border_color(char *arg) 380{ 381 int color; 382 383 if ((color = get_color_number(arg)) != -1) { 384 fprintf(stderr, "[=%dA", color); 385 } 386 else 387 usage(); 388} 389 390void 391set_mouse(char *arg) 392{ 393 struct mouse_info mouse; 394 395 if (!strcmp(arg, "on")) 396 mouse.operation = MOUSE_SHOW; 397 else if (!strcmp(arg, "off")) 398 mouse.operation = MOUSE_HIDE; 399 else { 400 warnx("argument to -m must either on or off"); 401 return; 402 } 403 ioctl(0, CONS_MOUSECTL, &mouse); 404} 405 406static char 407*adapter_name(int type) 408{ 409 static struct { 410 int type; 411 char *name; 412 } names[] = { 413 { KD_MONO, "MDA" }, 414 { KD_HERCULES, "Hercules" }, 415 { KD_CGA, "CGA" }, 416 { KD_EGA, "EGA" }, 417 { KD_VGA, "VGA" }, 418 { KD_PC98, "PC-98xx" }, 419 { -1, "Unknown" }, 420 }; 421 int i; 422 423 for (i = 0; names[i].type != -1; ++i) 424 if (names[i].type == type) 425 break; 426 return names[i].name; 427} 428 429void 430show_adapter_info(void) 431{ 432 struct video_adapter ad; 433 434 ad.va_index = 0; 435 if (ioctl(0, CONS_ADPINFO, &ad)) { 436 warn("failed to obtain adapter information"); 437 return; 438 } 439 440 printf("adapter %d:\n", ad.va_index); 441 printf(" type:%s%s (%d), flags:0x%08x, CRTC:0x%x\n", 442 (ad.va_flags & V_ADP_VESA) ? "VESA " : "", 443 adapter_name(ad.va_type), ad.va_type, 444 ad.va_flags, ad.va_crtc_addr); 445 printf(" initial mode:%d, current mode:%d, BIOS mode:%d\n", 446 ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode); 447} 448 449void 450show_mode_info(void) 451{ 452 struct video_info info; 453 char buf[80]; 454 int mode; 455 int c; 456 457 printf(" mode# flags type size " 458 "font window linear buffer\n"); 459 printf("---------------------------------------" 460 "---------------------------------------\n"); 461 for (mode = 0; mode < M_VESA_MODE_MAX; ++mode) { 462 info.vi_mode = mode; 463 if (ioctl(0, CONS_MODEINFO, &info)) 464 continue; 465 466 printf("%3d (0x%03x)", mode, mode); 467 printf(" 0x%08x", info.vi_flags); 468 if (info.vi_flags & V_INFO_GRAPHICS) { 469 c = 'G'; 470 snprintf(buf, sizeof(buf), "%dx%dx%d %d", 471 info.vi_width, info.vi_height, 472 info.vi_depth, info.vi_planes); 473 } else { 474 c = 'T'; 475 snprintf(buf, sizeof(buf), "%dx%d", 476 info.vi_width, info.vi_height); 477 } 478 printf(" %c %-15s", c, buf); 479 snprintf(buf, sizeof(buf), "%dx%d", 480 info.vi_cwidth, info.vi_cheight); 481 printf(" %-5s", buf); 482 printf(" 0x%05x %2dk %2dk", 483 info.vi_window, info.vi_window_size, 484 info.vi_window_gran); 485 printf(" 0x%08x %2dk\n", 486 info.vi_buffer, info.vi_buffer_size); 487 } 488} 489 490void 491show_info(char *arg) 492{ 493 if (!strcmp(arg, "adapter")) 494 show_adapter_info(); 495 else if (!strcmp(arg, "mode")) 496 show_mode_info(); 497 else { 498 warnx("argument to -i must either adapter or mode"); 499 return; 500 } 501} 502 503void 504test_frame() 505{ 506 int i; 507 508 fprintf(stdout, "[=0G\n\n"); 509 for (i=0; i<8; i++) { 510 fprintf(stdout, "[=15F[=0G %2d [=%dF%-16s" 511 "[=15F[=0G %2d [=%dF%-16s " 512 "[=15F %2d [=%dGBACKGROUND[=0G\n", 513 i, i, legal_colors[i], i+8, i+8, 514 legal_colors[i+8], i, i); 515 } 516 fprintf(stdout, "[=%dF[=%dG[=%dH[=%dI\n", 517 info.mv_norm.fore, info.mv_norm.back, 518 info.mv_rev.fore, info.mv_rev.back); 519} 520 521int 522main(int argc, char **argv) 523{ 524 int opt; 525 526 527 info.size = sizeof(info); 528 if (ioctl(0, CONS_GETINFO, &info) < 0) 529 err(1, "must be on a virtual console"); 530 while((opt = getopt(argc, argv, "b:c:df:i:l:Lm:r:s:t:x")) != -1) 531 switch(opt) { 532 case 'b': 533 set_border_color(optarg); 534 break; 535 case 'c': 536 set_cursor_type(optarg); 537 break; 538 case 'd': 539 print_scrnmap(); 540 break; 541 case 'f': 542 load_font(optarg, 543 nextarg(argc, argv, &optind, 'f')); 544 break; 545 case 'i': 546 show_info(optarg); 547 break; 548 case 'l': 549 load_scrnmap(optarg); 550 break; 551 case 'L': 552 load_default_scrnmap(); 553 break; 554 case 'm': 555 set_mouse(optarg); 556 break; 557 case 'r': 558 set_reverse_colors(argc, argv, &optind); 559 break; 560 case 's': 561 set_console(optarg); 562 break; 563 case 't': 564 set_screensaver_timeout(optarg); 565 break; 566 case 'x': 567 hex = 1; 568 break; 569 default: 570 usage(); 571 } 572 video_mode(argc, argv, &optind); 573 set_normal_colors(argc, argv, &optind); 574 if (optind < argc && !strcmp(argv[optind], "show")) { 575 test_frame(); 576 optind++; 577 } 578 if ((optind != argc) || (argc == 1)) 579 usage(); 580 return 0; 581} 582 583