2 * Copyright (c) 1994-1996 Søren Schmidt
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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 without specific prior written permission
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.
30 static const char rcsid[] =
42 #include <sys/consio.h>
43 #include <sys/errno.h>
44 #include <sys/types.h>
49 #define _VESA_800x600_DFL_COLS 80
50 #define _VESA_800x600_DFL_ROWS 25
51 #define _VESA_800x600_DFL_FNSZ 16
53 /* Screen dump modes */
54 #define DUMP_FMT_RAW 1
55 #define DUMP_FMT_TXT 2
56 /* Screen dump options */
59 /* Screen dump file format revision */
60 #define DUMP_FMT_REV 1
62 char legal_colors[16][16] = {
63 "black", "blue", "green", "cyan",
64 "red", "magenta", "brown", "white",
65 "grey", "lightblue", "lightgreen", "lightcyan",
66 "lightred", "lightmagenta", "yellow", "lightwhite"
70 int vesa_cols = _VESA_800x600_DFL_COLS;
71 int vesa_rows = _VESA_800x600_DFL_ROWS;
79 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
80 "usage: vidcontrol [-CdHLPpx] [-b color] [-c appearance] [-f [size] file]",
81 " [-g geometry] [-h size] [-i adapter | mode] [-l screen_map]",
82 " [-M char] [-m on | off] [-r foreground background]",
83 " [-S on | off] [-s number] [-t N | off] [mode]",
84 " [foreground [background]] [show]");
89 nextarg(int ac, char **av, int *indp, int oc, int strict)
92 return(av[(*indp)++]);
94 errx(1, "option requires two arguments -- %c", oc);
99 openguess(const char *a[], const char *b[], const char *c[], const char *d[], char **name)
104 for (i = 0; a[i] != NULL; i++) {
105 for (j = 0; b[j] != NULL; j++) {
106 for (k = 0; c[k] != NULL; k++) {
107 for (l = 0; d[l] != NULL; l++) {
108 asprintf(name, "%s%s%s%s", a[i], b[j],
110 f = fopen(*name, "r");
122 load_scrnmap(const char *filename)
128 const char *a[] = {"", SCRNMAP_PATH, NULL};
129 const char *b[] = {filename, NULL};
130 const char *c[] = {"", ".scm", NULL};
131 const char *d[] = {"", NULL};
133 fd = openguess(a, b, c, d, &name);
135 warn("screenmap file not found");
138 size = sizeof(scrnmap);
139 if (decode(fd, (char *)&scrnmap, size) != size) {
141 if (fread(&scrnmap, 1, size, fd) != (unsigned)size) {
142 warnx("bad screenmap file");
147 if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
148 warn("can't load screenmap");
153 load_default_scrnmap(void)
158 for (i=0; i<256; i++)
159 *((char*)&scrnmap + i) = i;
160 if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
161 warn("can't load default screenmap");
167 unsigned char map[256];
170 if (ioctl(0, GIO_SCRNMAP, &map) < 0) {
171 warn("getting screenmap");
174 for (i=0; i<sizeof(map); i++) {
175 if (i != 0 && i % 16 == 0)
176 fprintf(stdout, "\n");
178 fprintf(stdout, " %02x", map[i]);
180 fprintf(stdout, " %03d", map[i]);
182 fprintf(stdout, "\n");
191 if (fstat(fileno(file), &sb) == 0)
197 #define DATASIZE(x) ((x).w * (x).h * 256 / 8)
200 load_font(const char *type, const char *filename)
204 unsigned long io = 0; /* silence stupid gcc(1) in the Wall mode */
205 char *name, *fontmap, size_sufx[6];
206 const char *a[] = {"", FONT_PATH, NULL};
207 const char *b[] = {filename, NULL};
208 const char *c[] = {"", size_sufx, NULL};
209 const char *d[] = {"", ".fnt", NULL};
216 } sizes[] = {{8, 16, PIO_FONT8x16},
217 {8, 14, PIO_FONT8x14},
221 _info.size = sizeof(_info);
222 if (ioctl(0, CONS_GETINFO, &_info) == -1) {
223 warn("failed to obtain current video mode parameters");
226 snprintf(size_sufx, sizeof(size_sufx), "-8x%d", _info.font_size);
227 fd = openguess(a, b, c, d, &name);
229 warn("%s: can't load font file", filename);
234 if (sscanf(type, "%dx%d", &w, &h) == 2)
235 for (i = 0; sizes[i].w != 0; i++)
236 if (sizes[i].w == w && sizes[i].h == h) {
237 size = DATASIZE(sizes[i]);
242 warnx("%s: bad font size specification", type);
247 /* Apply heuristics */
251 size = DATASIZE(sizes[0]);
252 fontmap = (char*) malloc(size);
253 dsize[0] = decode(fd, fontmap, size);
254 dsize[1] = fsize(fd);
258 for (j = 0; j < 2; j++)
259 for (i = 0; sizes[i].w != 0; i++)
260 if (DATASIZE(sizes[i]) == dsize[j]) {
268 warnx("%s: can't guess font size", filename);
275 fontmap = (char*) malloc(size);
276 if (decode(fd, fontmap, size) != size) {
278 if (fsize(fd) != size || fread(fontmap, 1, size, fd) != (unsigned)size) {
279 warnx("%s: bad font file", filename);
285 if (ioctl(0, io, fontmap) < 0)
286 warn("can't load font");
292 set_screensaver_timeout(char *arg)
296 if (!strcmp(arg, "off"))
300 if ((*arg == '\0') || (nsec < 1)) {
301 warnx("argument must be a positive number");
305 if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
306 warn("setting screensaver period");
310 set_cursor_type(char *appearence)
314 if (!strcmp(appearence, "normal"))
316 else if (!strcmp(appearence, "blink"))
318 else if (!strcmp(appearence, "destructive"))
321 warnx("argument to -c must be normal, blink or destructive");
324 ioctl(0, CONS_CURSORTYPE, &type);
328 video_mode(int argc, char **argv, int *_index)
334 { "80x25", SW_TEXT_80x25 },
335 { "80x30", SW_TEXT_80x30 },
336 { "80x43", SW_TEXT_80x43 },
337 { "80x50", SW_TEXT_80x50 },
338 { "80x60", SW_TEXT_80x60 },
339 { "132x25", SW_TEXT_132x25 },
340 { "132x30", SW_TEXT_132x30 },
341 { "132x43", SW_TEXT_132x43 },
342 { "132x50", SW_TEXT_132x50 },
343 { "132x60", SW_TEXT_132x60 },
344 { "VGA_40x25", SW_VGA_C40x25 },
345 { "VGA_80x25", SW_VGA_C80x25 },
346 { "VGA_80x30", SW_VGA_C80x30 },
347 { "VGA_80x50", SW_VGA_C80x50 },
348 { "VGA_80x60", SW_VGA_C80x60 },
350 { "VGA_90x25", SW_VGA_C90x25 },
351 { "VGA_90x30", SW_VGA_C90x30 },
352 { "VGA_90x43", SW_VGA_C90x43 },
353 { "VGA_90x50", SW_VGA_C90x50 },
354 { "VGA_90x60", SW_VGA_C90x60 },
356 { "VGA_320x200", SW_VGA_CG320 },
357 { "EGA_80x25", SW_ENH_C80x25 },
358 { "EGA_80x43", SW_ENH_C80x43 },
359 { "VESA_132x25", SW_VESA_C132x25 },
360 { "VESA_132x43", SW_VESA_C132x43 },
361 { "VESA_132x50", SW_VESA_C132x50 },
362 { "VESA_132x60", SW_VESA_C132x60 },
363 { "VESA_800x600", SW_VESA_800x600 },
366 unsigned long mode = 0;
372 if (ioctl(0, CONS_GET, &cur_mode) < 0)
373 err(1, "cannot get the current video mode");
374 if (*_index < argc) {
375 for (i = 0; modes[i].name != NULL; ++i) {
376 if (!strcmp(argv[*_index], modes[i].name)) {
377 mode = modes[i].mode;
381 if (modes[i].name == NULL)
383 if (ioctl(0, mode, NULL) < 0) {
384 warn("cannot set videomode");
387 if (mode == SW_VESA_800x600) {
389 if ((vesa_cols * 8 > 800) || (vesa_cols <= 0)) {
390 warnx("incorrect number of columns: %d",
392 size[0] = _VESA_800x600_DFL_COLS;
397 if ((vesa_rows * _VESA_800x600_DFL_FNSZ > 600) ||
399 warnx("incorrect number of rows: %d",
401 size[1] = _VESA_800x600_DFL_ROWS;
406 size[2] = _VESA_800x600_DFL_FNSZ;
407 if (ioctl(0, KDRASTER, size)) {
409 if (cur_mode >= M_VESA_BASE)
411 _IO('V', cur_mode - M_VESA_BASE),
414 ioctl(0, _IO('S', cur_mode), NULL);
415 warnc(ioerr, "cannot activate raster display");
425 get_color_number(char *color)
430 if (!strcmp(color, legal_colors[i]))
436 set_normal_colors(int argc, char **argv, int *_index)
440 if (*_index < argc && (color = get_color_number(argv[*_index])) != -1) {
442 fprintf(stderr, "\033[=%dF", color);
444 && (color = get_color_number(argv[*_index])) != -1
447 fprintf(stderr, "\033[=%dG", color);
453 set_reverse_colors(int argc, char **argv, int *_index)
457 if ((color = get_color_number(argv[*(_index)-1])) != -1) {
458 fprintf(stderr, "\033[=%dH", color);
460 && (color = get_color_number(argv[*_index])) != -1
463 fprintf(stderr, "\033[=%dI", color);
469 set_console(char *arg)
473 if( !arg || strspn(arg,"0123456789") != strlen(arg)) {
474 warnx("bad console number");
479 if (n < 1 || n > 16) {
480 warnx("console number out of range");
481 } else if (ioctl(0, VT_ACTIVATE, (caddr_t) (long) n) == -1)
482 warn("ioctl(VT_ACTIVATE)");
486 set_border_color(char *arg)
490 if ((color = get_color_number(arg)) != -1) {
491 fprintf(stderr, "\033[=%dA", color);
498 set_mouse_char(char *arg)
500 struct mouse_info mouse;
503 l = strtol(arg, NULL, 0);
504 if ((l < 0) || (l > UCHAR_MAX - 3)) {
505 warnx("argument to -M must be 0 through %d", UCHAR_MAX - 3);
508 mouse.operation = MOUSE_MOUSECHAR;
509 mouse.u.mouse_char = (int)l;
510 ioctl(0, CONS_MOUSECTL, &mouse);
516 struct mouse_info mouse;
518 if (!strcmp(arg, "on"))
519 mouse.operation = MOUSE_SHOW;
520 else if (!strcmp(arg, "off"))
521 mouse.operation = MOUSE_HIDE;
523 warnx("argument to -m must be either on or off");
526 ioctl(0, CONS_MOUSECTL, &mouse);
530 set_lockswitch(char *arg)
534 if (!strcmp(arg, "off"))
536 else if (!strcmp(arg, "on"))
539 warnx("argument to -S must be either on or off");
542 if (ioctl(0, VT_LOCKSWITCH, &data) == -1)
543 warn("ioctl(VT_LOCKSWITCH)");
547 *adapter_name(int type)
554 { KD_HERCULES, "Hercules" },
558 { KD_PC98, "PC-98xx" },
564 for (i = 0; names[i].type != -1; ++i)
565 if (names[i].type == type)
567 return names[i].name;
571 show_adapter_info(void)
573 struct video_adapter_info ad;
576 if (ioctl(0, CONS_ADPINFO, &ad)) {
577 warn("failed to obtain adapter information");
581 printf("fb%d:\n", ad.va_index);
582 printf(" %.*s%d, type:%s%s (%d), flags:0x%x\n",
583 (int)sizeof(ad.va_name), ad.va_name, ad.va_unit,
584 (ad.va_flags & V_ADP_VESA) ? "VESA " : "",
585 adapter_name(ad.va_type), ad.va_type, ad.va_flags);
586 printf(" initial mode:%d, current mode:%d, BIOS mode:%d\n",
587 ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode);
588 printf(" frame buffer window:0x%zx, buffer size:0x%zx\n",
589 ad.va_window, ad.va_buffer_size);
590 printf(" window size:0x%zx, origin:0x%x\n",
591 ad.va_window_size, ad.va_window_orig);
592 printf(" display start address (%d, %d), scan line width:%d\n",
593 ad.va_disp_start.x, ad.va_disp_start.y, ad.va_line_width);
594 printf(" reserved:0x%zx\n", ad.va_unused0);
600 struct video_info _info;
605 printf(" mode# flags type size "
606 "font window linear buffer\n");
607 printf("---------------------------------------"
608 "---------------------------------------\n");
609 for (mode = 0; mode < M_VESA_MODE_MAX; ++mode) {
610 _info.vi_mode = mode;
611 if (ioctl(0, CONS_MODEINFO, &_info))
613 if (_info.vi_mode != mode)
616 printf("%3d (0x%03x)", mode, mode);
617 printf(" 0x%08x", _info.vi_flags);
618 if (_info.vi_flags & V_INFO_GRAPHICS) {
620 snprintf(buf, sizeof(buf), "%dx%dx%d %d",
621 _info.vi_width, _info.vi_height,
622 _info.vi_depth, _info.vi_planes);
625 snprintf(buf, sizeof(buf), "%dx%d",
626 _info.vi_width, _info.vi_height);
628 printf(" %c %-15s", c, buf);
629 snprintf(buf, sizeof(buf), "%dx%d",
630 _info.vi_cwidth, _info.vi_cheight);
631 printf(" %-5s", buf);
632 printf(" 0x%05zx %2dk %2dk",
633 _info.vi_window, (int)_info.vi_window_size/1024,
634 (int)_info.vi_window_gran/1024);
635 printf(" 0x%08zx %dk\n",
636 _info.vi_buffer, (int)_info.vi_buffer_size/1024);
643 if (!strcmp(arg, "adapter"))
645 else if (!strcmp(arg, "mode"))
648 warnx("argument to -i must be either adapter or mode");
656 int i, cur_mode, fore;
660 if (ioctl(0, CONS_GET, &cur_mode) < 0)
661 err(1, "must be on a virtual console");
669 fprintf(stdout, "\033[=0G\n\n");
670 for (i=0; i<8; i++) {
671 fprintf(stdout, "\033[=%dF\033[=0G %2d \033[=%dF%-16s"
672 "\033[=%dF\033[=0G %2d \033[=%dF%-16s "
673 "\033[=%dF %2d \033[=%dGBACKGROUND\033[=0G\n",
674 fore, i, i, legal_colors[i],
675 fore, i+8, i+8, legal_colors[i+8],
678 fprintf(stdout, "\033[=%dF\033[=%dG\033[=%dH\033[=%dI\n",
679 info.mv_norm.fore, info.mv_norm.back,
680 info.mv_rev.fore, info.mv_rev.back);
684 * Snapshot the video memory of that terminal, using the CONS_SCRSHOT
685 * ioctl, and writes the results to stdout either in the special
686 * binary format (see manual page for details), or in the plain
690 dump_screen(int mode, int opt)
695 _info.size = sizeof(_info);
696 if (ioctl(0, CONS_GETINFO, &_info) == -1) {
697 warn("failed to obtain current video mode parameters");
702 shot.xsize = _info.mv_csz;
703 shot.ysize = _info.mv_rsz;
705 shot.ysize += _info.mv_hsz;
707 shot.buf = alloca(shot.xsize * shot.ysize * sizeof(u_int16_t));
708 if (shot.buf == NULL) {
709 warn("failed to allocate memory for dump");
713 if (ioctl(0, CONS_SCRSHOT, &shot) == -1) {
714 warn("failed to get dump of the screen");
718 if (mode == DUMP_FMT_RAW) {
719 printf("SCRSHOT_%c%c%c%c", DUMP_FMT_REV, 2,
720 shot.xsize, shot.ysize);
723 (void)write(STDOUT_FILENO, shot.buf,
724 shot.xsize * shot.ysize * sizeof(u_int16_t));
730 line = alloca(shot.xsize + 1);
732 warn("failed to allocate memory for line buffer");
736 for (y = 0; y < shot.ysize; y++) {
737 for (x = 0; x < shot.xsize; x++) {
738 ch = shot.buf[x + (y * shot.xsize)];
740 if (isprint(ch) == 0)
745 /* Trim trailing spaces */
748 } while (line[x] == ' ' && x != 0);
759 set_history(char *opt)
764 if ((*opt == '\0') || size < 0) {
765 warnx("argument must be a positive number");
768 if (ioctl(0, CONS_HISTORY, &size) == -1)
769 warn("setting history buffer size");
776 if (ioctl(0, CONS_CLRHIST) == -1)
777 warn("clear history buffer");
781 main(int argc, char **argv)
784 int dumpmod, dumpopt, opt;
787 info.size = sizeof(info);
791 if (ioctl(0, CONS_GETINFO, &info) < 0)
792 err(1, "must be on a virtual console");
795 while((opt = getopt(argc, argv, "b:Cc:df:g:h:Hi:l:LM:m:pPr:S:s:t:x")) != -1)
798 set_border_color(optarg);
804 set_cursor_type(optarg);
811 font = nextarg(argc, argv, &optind, 'f', 0);
816 load_font(type, font);
819 if (sscanf(optarg, "%dx%d", &vesa_cols,
821 warnx("incorrect geometry: %s", optarg);
835 load_scrnmap(optarg);
838 load_default_scrnmap();
841 set_mouse_char(optarg);
847 dumpmod = DUMP_FMT_RAW;
850 dumpmod = DUMP_FMT_TXT;
853 set_reverse_colors(argc, argv, &optind);
856 set_lockswitch(optarg);
862 set_screensaver_timeout(optarg);
871 dump_screen(dumpmod, dumpopt);
872 reterr = video_mode(argc, argv, &optind);
873 set_normal_colors(argc, argv, &optind);
874 if (optind < argc && !strcmp(argv[optind], "show")) {
878 if ((optind != argc) || (argc == 1))