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