12089Ssos/*-
2228976Suqs * Copyright (c) 1994-1996 S��ren Schmidt
32089Ssos * All rights reserved.
42089Ssos *
5146736Sdelphij * Portions of this software are based in part on the work of
6146736Sdelphij * Sascha Wildner <saw@online.de> contributed to The DragonFly Project
7146736Sdelphij *
82089Ssos * Redistribution and use in source and binary forms, with or without
92089Ssos * modification, are permitted provided that the following conditions
102089Ssos * are met:
112089Ssos * 1. Redistributions of source code must retain the above copyright
125994Ssos *    notice, this list of conditions and the following disclaimer,
135994Ssos *    in this position and unchanged.
142089Ssos * 2. Redistributions in binary form must reproduce the above copyright
152089Ssos *    notice, this list of conditions and the following disclaimer in the
162089Ssos *    documentation and/or other materials provided with the distribution.
172089Ssos * 3. The name of the author may not be used to endorse or promote products
1897748Sschweikh *    derived from this software without specific prior written permission
192089Ssos *
202089Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
212089Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
222089Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
232089Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
242089Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
252089Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
262089Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
272089Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
282089Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
292089Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30146736Sdelphij *
31146736Sdelphij * $DragonFly: src/usr.sbin/vidcontrol/vidcontrol.c,v 1.10 2005/03/02 06:08:29 joerg Exp $
322089Ssos */
332089Ssos
3430764Scharnier#ifndef lint
3530764Scharnierstatic const char rcsid[] =
3650479Speter  "$FreeBSD: releng/10.3/usr.sbin/vidcontrol/vidcontrol.c 286291 2015-08-04 15:15:06Z emaste $";
3730764Scharnier#endif /* not lint */
3830764Scharnier
392089Ssos#include <ctype.h>
4030764Scharnier#include <err.h>
4155849Syokota#include <limits.h>
422089Ssos#include <stdio.h>
4323457Sbrian#include <stdlib.h>
4430764Scharnier#include <string.h>
4523702Speter#include <unistd.h>
4666834Sphk#include <sys/fbio.h>
4766834Sphk#include <sys/consio.h>
48267540Sray#include <sys/endian.h>
492089Ssos#include <sys/errno.h>
50267540Sray#include <sys/param.h>
5175344Ssobomax#include <sys/types.h>
5275344Ssobomax#include <sys/stat.h>
53267540Sray#include <sys/sysctl.h>
542089Ssos#include "path.h"
5523457Sbrian#include "decode.h"
562089Ssos
5771642Ssobomax
58146736Sdelphij#define	DATASIZE(x)	((x).w * (x).h * 256 / 8)
59146736Sdelphij
60102111Ssobomax/* Screen dump modes */
61102111Ssobomax#define DUMP_FMT_RAW	1
62102111Ssobomax#define DUMP_FMT_TXT	2
63102111Ssobomax/* Screen dump options */
64102111Ssobomax#define DUMP_FBF	0
65102111Ssobomax#define DUMP_ALL	1
66102111Ssobomax/* Screen dump file format revision */
6776845Ssobomax#define DUMP_FMT_REV	1
6876845Ssobomax
69228425Sedstatic const char *legal_colors[16] = {
702089Ssos	"black", "blue", "green", "cyan",
712089Ssos	"red", "magenta", "brown", "white",
722089Ssos	"grey", "lightblue", "lightgreen", "lightcyan",
732089Ssos	"lightred", "lightmagenta", "yellow", "lightwhite"
746628Ssos};
752089Ssos
76241737Sedstatic struct {
77146736Sdelphij	int			active_vty;
78146736Sdelphij	vid_info_t		console_info;
79146736Sdelphij	unsigned char		screen_map[256];
80146736Sdelphij	int			video_mode_number;
81146736Sdelphij	struct video_info	video_mode_info;
82146736Sdelphij} cur_info;
832089Ssos
84267540Sraystruct vt4font_header {
85267540Sray	uint8_t		magic[8];
86267540Sray	uint8_t		width;
87267540Sray	uint8_t		height;
88267540Sray	uint16_t	pad;
89267540Sray	uint32_t	glyph_count;
90267540Sray	uint32_t	map_count[4];
91267540Sray} __packed;
92267540Sray
93228425Sedstatic int	hex = 0;
94228425Sedstatic int	vesa_cols;
95228425Sedstatic int	vesa_rows;
96228425Sedstatic int	font_height;
97228425Sedstatic int	colors_changed;
98228425Sedstatic int	video_mode_changed;
99228425Sedstatic int	normal_fore_color, normal_back_color;
100228425Sedstatic int	revers_fore_color, revers_back_color;
101267540Sraystatic int	vt4_mode = 0;
102228425Sedstatic struct	vid_info info;
103228425Sedstatic struct	video_info new_mode_info;
104146736Sdelphij
105146736Sdelphij
106146736Sdelphij/*
107146736Sdelphij * Initialize revert data.
108146736Sdelphij *
109146736Sdelphij * NOTE: the following parameters are not yet saved/restored:
110146736Sdelphij *
111146736Sdelphij *   screen saver timeout
112146736Sdelphij *   cursor type
113146736Sdelphij *   mouse character and mouse show/hide state
114146736Sdelphij *   vty switching on/off state
115146736Sdelphij *   history buffer size
116146736Sdelphij *   history contents
117146736Sdelphij *   font maps
118146736Sdelphij */
119146736Sdelphij
12030764Scharnierstatic void
121146736Sdelphijinit(void)
122146736Sdelphij{
123146736Sdelphij	if (ioctl(0, VT_GETACTIVE, &cur_info.active_vty) == -1)
124146736Sdelphij		errc(1, errno, "getting active vty");
125146736Sdelphij
126146736Sdelphij	cur_info.console_info.size = sizeof(cur_info.console_info);
127146736Sdelphij
128146736Sdelphij	if (ioctl(0, CONS_GETINFO, &cur_info.console_info) == -1)
129146736Sdelphij		errc(1, errno, "getting console information");
130146736Sdelphij
131267540Sray	/* vt(4) use unicode, so no screen mapping required. */
132267540Sray	if (vt4_mode == 0 &&
133267540Sray	    ioctl(0, GIO_SCRNMAP, &cur_info.screen_map) == -1)
134146736Sdelphij		errc(1, errno, "getting screen map");
135146736Sdelphij
136146736Sdelphij	if (ioctl(0, CONS_GET, &cur_info.video_mode_number) == -1)
137146736Sdelphij		errc(1, errno, "getting video mode number");
138146736Sdelphij
139146736Sdelphij	cur_info.video_mode_info.vi_mode = cur_info.video_mode_number;
140146736Sdelphij
141146736Sdelphij	if (ioctl(0, CONS_MODEINFO, &cur_info.video_mode_info) == -1)
142146736Sdelphij		errc(1, errno, "getting video mode parameters");
143146736Sdelphij
144146736Sdelphij	normal_fore_color = cur_info.console_info.mv_norm.fore;
145146736Sdelphij	normal_back_color = cur_info.console_info.mv_norm.back;
146146736Sdelphij	revers_fore_color = cur_info.console_info.mv_rev.fore;
147146736Sdelphij	revers_back_color = cur_info.console_info.mv_rev.back;
148146736Sdelphij}
149146736Sdelphij
150146736Sdelphij
151146736Sdelphij/*
152146736Sdelphij * If something goes wrong along the way we call revert() to go back to the
153146736Sdelphij * console state we came from (which is assumed to be working).
154146736Sdelphij *
155146736Sdelphij * NOTE: please also read the comments of init().
156146736Sdelphij */
157146736Sdelphij
158146736Sdelphijstatic void
159146736Sdelphijrevert(void)
160146736Sdelphij{
161146736Sdelphij	int size[3];
162146736Sdelphij
163162671Sru	ioctl(0, VT_ACTIVATE, cur_info.active_vty);
164146736Sdelphij
165146736Sdelphij	fprintf(stderr, "\033[=%dA", cur_info.console_info.mv_ovscan);
166146736Sdelphij	fprintf(stderr, "\033[=%dF", cur_info.console_info.mv_norm.fore);
167146736Sdelphij	fprintf(stderr, "\033[=%dG", cur_info.console_info.mv_norm.back);
168146736Sdelphij	fprintf(stderr, "\033[=%dH", cur_info.console_info.mv_rev.fore);
169146736Sdelphij	fprintf(stderr, "\033[=%dI", cur_info.console_info.mv_rev.back);
170146736Sdelphij
171267540Sray	if (vt4_mode == 0)
172267540Sray		ioctl(0, PIO_SCRNMAP, &cur_info.screen_map);
173146736Sdelphij
174146736Sdelphij	if (cur_info.video_mode_number >= M_VESA_BASE)
175146736Sdelphij		ioctl(0, _IO('V', cur_info.video_mode_number - M_VESA_BASE),
176146736Sdelphij		      NULL);
177146736Sdelphij	else
178146736Sdelphij		ioctl(0, _IO('S', cur_info.video_mode_number), NULL);
179146736Sdelphij
180146736Sdelphij	if (cur_info.video_mode_info.vi_flags & V_INFO_GRAPHICS) {
181146736Sdelphij		size[0] = cur_info.video_mode_info.vi_width / 8;
182146736Sdelphij		size[1] = cur_info.video_mode_info.vi_height /
183146736Sdelphij			  cur_info.console_info.font_size;
184146736Sdelphij		size[2] = cur_info.console_info.font_size;
185146736Sdelphij
186146736Sdelphij		ioctl(0, KDRASTER, size);
187146736Sdelphij	}
188146736Sdelphij}
189146736Sdelphij
190146736Sdelphij
191146736Sdelphij/*
192146736Sdelphij * Print a short usage string describing all options, then exit.
193146736Sdelphij */
194146736Sdelphij
195146736Sdelphijstatic void
196140159Sdelphijusage(void)
1976628Ssos{
198267540Sray	if (vt4_mode)
199267540Sray		fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
200273921Sdumbbell"usage: vidcontrol [-CHPpx] [-b color] [-c appearance] [-f [[size] file]]",
201267540Sray"                  [-g geometry] [-h size] [-i adapter | mode]",
202267540Sray"                  [-M char] [-m on | off] [-r foreground background]",
203267540Sray"                  [-S on | off] [-s number] [-T xterm | cons25] [-t N | off]",
204267540Sray"                  [mode] [foreground [background]] [show]");
205267540Sray	else
206267540Sray		fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
207102111Ssobomax"usage: vidcontrol [-CdHLPpx] [-b color] [-c appearance] [-f [size] file]",
20877329Sdes"                  [-g geometry] [-h size] [-i adapter | mode] [-l screen_map]",
20999706Sdd"                  [-M char] [-m on | off] [-r foreground background]",
210199174Sed"                  [-S on | off] [-s number] [-T xterm | cons25] [-t N | off]",
211199174Sed"                  [mode] [foreground [background]] [show]");
21230764Scharnier	exit(1);
2136628Ssos}
2146628Ssos
215267540Sray/* Detect presence of vt(4). */
216267540Sraystatic int
217267540Srayis_vt4(void)
218267540Sray{
219268366Sray	char vty_name[4] = "";
220268366Sray	size_t len = sizeof(vty_name);
221146736Sdelphij
222268366Sray	if (sysctlbyname("kern.vty", vty_name, &len, NULL, 0) != 0)
223268366Sray		return (0);
224268366Sray	return (strcmp(vty_name, "vt") == 0);
225267540Sray}
226267540Sray
227146736Sdelphij/*
228146736Sdelphij * Retrieve the next argument from the command line (for options that require
229146736Sdelphij * more than one argument).
230146736Sdelphij */
231146736Sdelphij
232140159Sdelphijstatic char *
23375344Ssobomaxnextarg(int ac, char **av, int *indp, int oc, int strict)
2342089Ssos{
2352089Ssos	if (*indp < ac)
2362089Ssos		return(av[(*indp)++]);
237146736Sdelphij
238146736Sdelphij	if (strict != 0) {
239146736Sdelphij		revert();
24075344Ssobomax		errx(1, "option requires two arguments -- %c", oc);
241146736Sdelphij	}
242146736Sdelphij
24375344Ssobomax	return(NULL);
2442089Ssos}
2452089Ssos
246146736Sdelphij
247146736Sdelphij/*
248146736Sdelphij * Guess which file to open. Try to open each combination of a specified set
249146736Sdelphij * of file name components.
250146736Sdelphij */
251146736Sdelphij
252140159Sdelphijstatic FILE *
253140159Sdelphijopenguess(const char *a[], const char *b[], const char *c[], const char *d[], char **name)
2542089Ssos{
25592460Ssobomax	FILE *f;
25692460Ssobomax	int i, j, k, l;
2572089Ssos
25892460Ssobomax	for (i = 0; a[i] != NULL; i++) {
25992460Ssobomax		for (j = 0; b[j] != NULL; j++) {
26092460Ssobomax			for (k = 0; c[k] != NULL; k++) {
26192460Ssobomax				for (l = 0; d[l] != NULL; l++) {
262146736Sdelphij					asprintf(name, "%s%s%s%s",
263146736Sdelphij						 a[i], b[j], c[k], d[l]);
264146736Sdelphij
26592460Ssobomax					f = fopen(*name, "r");
266146736Sdelphij
26792460Ssobomax					if (f != NULL)
26892460Ssobomax						return (f);
269146736Sdelphij
27092460Ssobomax					free(*name);
27192460Ssobomax				}
27292460Ssobomax			}
27392460Ssobomax		}
27452262Sbillf	}
27592460Ssobomax	return (NULL);
2762089Ssos}
2772089Ssos
278146736Sdelphij
279146736Sdelphij/*
280146736Sdelphij * Load a screenmap from a file and set it.
281146736Sdelphij */
282146736Sdelphij
283140159Sdelphijstatic void
284140159Sdelphijload_scrnmap(const char *filename)
2852089Ssos{
28692460Ssobomax	FILE *fd;
28792460Ssobomax	int size;
2882089Ssos	char *name;
2892089Ssos	scrmap_t scrnmap;
290140159Sdelphij	const char *a[] = {"", SCRNMAP_PATH, NULL};
291140159Sdelphij	const char *b[] = {filename, NULL};
292140159Sdelphij	const char *c[] = {"", ".scm", NULL};
293140159Sdelphij	const char *d[] = {"", NULL};
2942089Ssos
29592460Ssobomax	fd = openguess(a, b, c, d, &name);
296146736Sdelphij
2972089Ssos	if (fd == NULL) {
298146736Sdelphij		revert();
299146736Sdelphij		errx(1, "screenmap file not found");
3002089Ssos	}
301146736Sdelphij
3022089Ssos	size = sizeof(scrnmap);
303146736Sdelphij
30475344Ssobomax	if (decode(fd, (char *)&scrnmap, size) != size) {
3052089Ssos		rewind(fd);
306146736Sdelphij
307146736Sdelphij		if (fread(&scrnmap, 1, size, fd) != (size_t)size) {
30830764Scharnier			warnx("bad screenmap file");
30923457Sbrian			fclose(fd);
310146736Sdelphij			revert();
311146736Sdelphij			errx(1, "bad screenmap file");
3122089Ssos		}
3132089Ssos	}
314146736Sdelphij
315146736Sdelphij	if (ioctl(0, PIO_SCRNMAP, &scrnmap) == -1) {
316146736Sdelphij		revert();
317146736Sdelphij		errc(1, errno, "loading screenmap");
318146736Sdelphij	}
319146736Sdelphij
32023457Sbrian	fclose(fd);
3212089Ssos}
3222089Ssos
323146736Sdelphij
324146736Sdelphij/*
325146736Sdelphij * Set the default screenmap.
326146736Sdelphij */
327146736Sdelphij
328140159Sdelphijstatic void
329140159Sdelphijload_default_scrnmap(void)
3302089Ssos{
3316628Ssos	scrmap_t scrnmap;
3322089Ssos	int i;
3332089Ssos
3342089Ssos	for (i=0; i<256; i++)
3352089Ssos		*((char*)&scrnmap + i) = i;
336146736Sdelphij
337146736Sdelphij	if (ioctl(0, PIO_SCRNMAP, &scrnmap) == -1) {
338146736Sdelphij		revert();
339146736Sdelphij		errc(1, errno, "loading default screenmap");
340146736Sdelphij	}
3412089Ssos}
3422089Ssos
343146736Sdelphij
344146736Sdelphij/*
345146736Sdelphij * Print the current screenmap to stdout.
346146736Sdelphij */
347146736Sdelphij
348140159Sdelphijstatic void
349140159Sdelphijprint_scrnmap(void)
3502089Ssos{
3512089Ssos	unsigned char map[256];
352140159Sdelphij	size_t i;
3532089Ssos
354146736Sdelphij	if (ioctl(0, GIO_SCRNMAP, &map) == -1) {
355146736Sdelphij		revert();
356146736Sdelphij		errc(1, errno, "getting screenmap");
3572089Ssos	}
3582089Ssos	for (i=0; i<sizeof(map); i++) {
359140159Sdelphij		if (i != 0 && i % 16 == 0)
3602089Ssos			fprintf(stdout, "\n");
361146736Sdelphij
362146736Sdelphij		if (hex != 0)
3638857Srgrimes			fprintf(stdout, " %02x", map[i]);
3642089Ssos		else
3652089Ssos			fprintf(stdout, " %03d", map[i]);
3662089Ssos	}
3672089Ssos	fprintf(stdout, "\n");
3682089Ssos
3692089Ssos}
3702089Ssos
371146736Sdelphij
372146736Sdelphij/*
373146736Sdelphij * Determine a file's size.
374146736Sdelphij */
375146736Sdelphij
376140159Sdelphijstatic int
37775344Ssobomaxfsize(FILE *file)
37875344Ssobomax{
37975344Ssobomax	struct stat sb;
38075344Ssobomax
38175344Ssobomax	if (fstat(fileno(file), &sb) == 0)
38275344Ssobomax		return sb.st_size;
38375344Ssobomax	else
38475344Ssobomax		return -1;
38575344Ssobomax}
38675344Ssobomax
387267540Sraystatic vfnt_map_t *
388267540Srayload_vt4mappingtable(unsigned int nmappings, FILE *f)
389267540Sray{
390267540Sray	vfnt_map_t *t;
391267540Sray	unsigned int i;
39275344Ssobomax
393267540Sray	if (nmappings == 0)
394267540Sray		return (NULL);
395267540Sray
396267540Sray	t = malloc(sizeof *t * nmappings);
397267540Sray
398267540Sray	if (fread(t, sizeof *t * nmappings, 1, f) != 1) {
399267540Sray		perror("mappings");
400267540Sray		exit(1);
401267540Sray	}
402267540Sray
403267540Sray	for (i = 0; i < nmappings; i++) {
404267540Sray		t[i].src = be32toh(t[i].src);
405267540Sray		t[i].dst = be16toh(t[i].dst);
406267540Sray		t[i].len = be16toh(t[i].len);
407267540Sray	}
408267540Sray
409267540Sray	return (t);
410267540Sray}
411267540Sray
412273921Sdumbbell/*
413273921Sdumbbell * Set the default vt font.
414273921Sdumbbell */
415273921Sdumbbell
416273921Sdumbbellstatic void
417273921Sdumbbellload_default_vt4font(void)
418273921Sdumbbell{
419273921Sdumbbell	if (ioctl(0, PIO_VFONT_DEFAULT) == -1) {
420273921Sdumbbell		revert();
421273921Sdumbbell		errc(1, errno, "loading default vt font");
422273921Sdumbbell	}
423273921Sdumbbell}
424273921Sdumbbell
425267540Sraystatic int
426267540Srayload_vt4font(FILE *f)
427267540Sray{
428267540Sray	struct vt4font_header fh;
429267540Sray	static vfnt_t vfnt;
430267540Sray	size_t glyphsize;
431267540Sray	unsigned int i;
432267540Sray
433267540Sray	if (fread(&fh, sizeof fh, 1, f) != 1) {
434267540Sray		perror("file_header");
435267540Sray		return (1);
436267540Sray	}
437267540Sray
438267540Sray	if (memcmp(fh.magic, "VFNT0002", 8) != 0) {
439267540Sray		fprintf(stderr, "Bad magic\n");
440267540Sray		return (1);
441267540Sray	}
442267540Sray
443267540Sray	for (i = 0; i < VFNT_MAPS; i++)
444267540Sray		vfnt.map_count[i] = be32toh(fh.map_count[i]);
445267540Sray	vfnt.glyph_count = be32toh(fh.glyph_count);
446267540Sray	vfnt.width = fh.width;
447267540Sray	vfnt.height = fh.height;
448267540Sray
449267540Sray	glyphsize = howmany(vfnt.width, 8) * vfnt.height * vfnt.glyph_count;
450267540Sray	vfnt.glyphs = malloc(glyphsize);
451267540Sray
452267540Sray	if (fread(vfnt.glyphs, glyphsize, 1, f) != 1) {
453267540Sray		perror("glyphs");
454267540Sray		return (1);
455267540Sray	}
456267540Sray
457267540Sray	for (i = 0; i < VFNT_MAPS; i++)
458267540Sray		vfnt.map[i] = load_vt4mappingtable(vfnt.map_count[i], f);
459267540Sray
460267540Sray	if (ioctl(STDIN_FILENO, PIO_VFONT, &vfnt) == -1) {
461267540Sray		perror("PIO_VFONT");
462267540Sray		return (1);
463267540Sray	}
464267540Sray	return (0);
465267540Sray}
466267540Sray
467146736Sdelphij/*
468146736Sdelphij * Load a font from file and set it.
469146736Sdelphij */
470146736Sdelphij
471140159Sdelphijstatic void
472140159Sdelphijload_font(const char *type, const char *filename)
4732089Ssos{
47492460Ssobomax	FILE	*fd;
47575344Ssobomax	int	h, i, size, w;
47675344Ssobomax	unsigned long io = 0;	/* silence stupid gcc(1) in the Wall mode */
47792460Ssobomax	char	*name, *fontmap, size_sufx[6];
478140159Sdelphij	const char	*a[] = {"", FONT_PATH, NULL};
479267540Sray	const char	*vt4a[] = {"", VT_FONT_PATH, NULL};
480140159Sdelphij	const char	*b[] = {filename, NULL};
481140159Sdelphij	const char	*c[] = {"", size_sufx, NULL};
482140159Sdelphij	const char	*d[] = {"", ".fnt", NULL};
483140159Sdelphij	vid_info_t _info;
4842089Ssos
48575344Ssobomax	struct sizeinfo {
48675344Ssobomax		int w;
48775344Ssobomax		int h;
48875344Ssobomax		unsigned long io;
48975344Ssobomax	} sizes[] = {{8, 16, PIO_FONT8x16},
49075344Ssobomax		     {8, 14, PIO_FONT8x14},
49175344Ssobomax		     {8,  8,  PIO_FONT8x8},
49275344Ssobomax		     {0,  0,            0}};
49375344Ssobomax
494267540Sray	if (vt4_mode) {
495267540Sray		size_sufx[0] = '\0';
496267540Sray	} else {
497267540Sray		_info.size = sizeof(_info);
498267540Sray		if (ioctl(0, CONS_GETINFO, &_info) == -1) {
499267540Sray			revert();
500267540Sray			warn("failed to obtain current video mode parameters");
501267540Sray			return;
502267540Sray		}
503267540Sray
504267540Sray		snprintf(size_sufx, sizeof(size_sufx), "-8x%d", _info.font_size);
5052089Ssos	}
506267540Sray	fd = openguess((vt4_mode == 0) ? a : vt4a, b, c, d, &name);
507146736Sdelphij
5082089Ssos	if (fd == NULL) {
509146736Sdelphij		revert();
510146736Sdelphij		errx(1, "%s: can't load font file", filename);
5112089Ssos	}
512146736Sdelphij
513267540Sray	if (vt4_mode) {
514267540Sray		if(load_vt4font(fd))
515267540Sray			warn("failed to load font \"%s\"", filename);
516267540Sray		fclose(fd);
517267540Sray		return;
518267540Sray	}
519267540Sray
52075344Ssobomax	if (type != NULL) {
52175344Ssobomax		size = 0;
522146736Sdelphij		if (sscanf(type, "%dx%d", &w, &h) == 2) {
523146736Sdelphij			for (i = 0; sizes[i].w != 0; i++) {
52475344Ssobomax				if (sizes[i].w == w && sizes[i].h == h) {
52575344Ssobomax					size = DATASIZE(sizes[i]);
52675344Ssobomax					io = sizes[i].io;
527146736Sdelphij					font_height = sizes[i].h;
52875344Ssobomax				}
529146736Sdelphij			}
530146736Sdelphij		}
53175344Ssobomax		if (size == 0) {
53275344Ssobomax			fclose(fd);
533146736Sdelphij			revert();
534146736Sdelphij			errx(1, "%s: bad font size specification", type);
53575344Ssobomax		}
53675344Ssobomax	} else {
53775344Ssobomax		/* Apply heuristics */
538146736Sdelphij
53975344Ssobomax		int j;
54075344Ssobomax		int dsize[2];
54175344Ssobomax
54275344Ssobomax		size = DATASIZE(sizes[0]);
54375344Ssobomax		fontmap = (char*) malloc(size);
54475344Ssobomax		dsize[0] = decode(fd, fontmap, size);
54575344Ssobomax		dsize[1] = fsize(fd);
54675344Ssobomax		free(fontmap);
54775344Ssobomax
54875344Ssobomax		size = 0;
549146736Sdelphij		for (j = 0; j < 2; j++) {
550146736Sdelphij			for (i = 0; sizes[i].w != 0; i++) {
55175344Ssobomax				if (DATASIZE(sizes[i]) == dsize[j]) {
55275344Ssobomax					size = dsize[j];
55375344Ssobomax					io = sizes[i].io;
554146736Sdelphij					font_height = sizes[i].h;
55575344Ssobomax					j = 2;	/* XXX */
55675344Ssobomax					break;
55775344Ssobomax				}
558146736Sdelphij			}
559146736Sdelphij		}
56075344Ssobomax
56175344Ssobomax		if (size == 0) {
56275344Ssobomax			fclose(fd);
563146736Sdelphij			revert();
564146736Sdelphij			errx(1, "%s: can't guess font size", filename);
56575344Ssobomax		}
566146736Sdelphij
56775344Ssobomax		rewind(fd);
5682089Ssos	}
56975344Ssobomax
5702089Ssos	fontmap = (char*) malloc(size);
571146736Sdelphij
57275344Ssobomax	if (decode(fd, fontmap, size) != size) {
5732089Ssos		rewind(fd);
574146736Sdelphij		if (fsize(fd) != size ||
575146736Sdelphij		    fread(fontmap, 1, size, fd) != (size_t)size) {
57675344Ssobomax			warnx("%s: bad font file", filename);
57723457Sbrian			fclose(fd);
5782089Ssos			free(fontmap);
579146736Sdelphij			revert();
580146736Sdelphij			errx(1, "%s: bad font file", filename);
5812089Ssos		}
5822089Ssos	}
583146736Sdelphij
584146736Sdelphij	if (ioctl(0, io, fontmap) == -1) {
585146736Sdelphij		revert();
586146736Sdelphij		errc(1, errno, "loading font");
587146736Sdelphij	}
588146736Sdelphij
58923457Sbrian	fclose(fd);
5902089Ssos	free(fontmap);
5912089Ssos}
5922089Ssos
593146736Sdelphij
594146736Sdelphij/*
595146736Sdelphij * Set the timeout for the screensaver.
596146736Sdelphij */
597146736Sdelphij
598140159Sdelphijstatic void
5992089Ssosset_screensaver_timeout(char *arg)
6002089Ssos{
6012089Ssos	int nsec;
6022089Ssos
603146736Sdelphij	if (!strcmp(arg, "off")) {
6042089Ssos		nsec = 0;
605146736Sdelphij	} else {
6062089Ssos		nsec = atoi(arg);
607146736Sdelphij
6082089Ssos		if ((*arg == '\0') || (nsec < 1)) {
609146736Sdelphij			revert();
610146736Sdelphij			errx(1, "argument must be a positive number");
6112089Ssos		}
6122089Ssos	}
613146736Sdelphij
614146736Sdelphij	if (ioctl(0, CONS_BLANKTIME, &nsec) == -1) {
615146736Sdelphij		revert();
616146736Sdelphij		errc(1, errno, "setting screensaver period");
617146736Sdelphij	}
6182089Ssos}
6192089Ssos
620146736Sdelphij
621146736Sdelphij/*
622146736Sdelphij * Set the cursor's shape/type.
623146736Sdelphij */
624146736Sdelphij
625140159Sdelphijstatic void
626228990Suqsset_cursor_type(char *appearance)
6272089Ssos{
6285536Ssos	int type;
6292089Ssos
630228990Suqs	if (!strcmp(appearance, "normal"))
6316230Ssos		type = 0;
632228990Suqs	else if (!strcmp(appearance, "blink"))
6335536Ssos		type = 1;
634228990Suqs	else if (!strcmp(appearance, "destructive"))
6356230Ssos		type = 3;
6365536Ssos	else {
637146736Sdelphij		revert();
638146736Sdelphij		errx(1, "argument to -c must be normal, blink or destructive");
6392089Ssos	}
640146736Sdelphij
641146736Sdelphij	if (ioctl(0, CONS_CURSORTYPE, &type) == -1) {
642146736Sdelphij		revert();
643146736Sdelphij		errc(1, errno, "setting cursor type");
644146736Sdelphij	}
6452089Ssos}
6462089Ssos
647146736Sdelphij
648146736Sdelphij/*
649146736Sdelphij * Set the video mode.
650146736Sdelphij */
651146736Sdelphij
652140159Sdelphijstatic int
653146736Sdelphijvideo_mode(int argc, char **argv, int *mode_index)
6542089Ssos{
65539592Syokota	static struct {
656140159Sdelphij		const char *name;
65739592Syokota		unsigned long mode;
658146736Sdelphij		unsigned long mode_num;
65939592Syokota	} modes[] = {
660146736Sdelphij		{ "80x25",        SW_TEXT_80x25,   M_TEXT_80x25 },
661146736Sdelphij		{ "80x30",        SW_TEXT_80x30,   M_TEXT_80x30 },
662146736Sdelphij		{ "80x43",        SW_TEXT_80x43,   M_TEXT_80x43 },
663146736Sdelphij		{ "80x50",        SW_TEXT_80x50,   M_TEXT_80x50 },
664146736Sdelphij		{ "80x60",        SW_TEXT_80x60,   M_TEXT_80x60 },
665146736Sdelphij		{ "132x25",       SW_TEXT_132x25,  M_TEXT_132x25 },
666146736Sdelphij		{ "132x30",       SW_TEXT_132x30,  M_TEXT_132x30 },
667146736Sdelphij		{ "132x43",       SW_TEXT_132x43,  M_TEXT_132x43 },
668146736Sdelphij		{ "132x50",       SW_TEXT_132x50,  M_TEXT_132x50 },
669146736Sdelphij		{ "132x60",       SW_TEXT_132x60,  M_TEXT_132x60 },
670146736Sdelphij		{ "VGA_40x25",    SW_VGA_C40x25,   M_VGA_C40x25 },
671146736Sdelphij		{ "VGA_80x25",    SW_VGA_C80x25,   M_VGA_C80x25 },
672146736Sdelphij		{ "VGA_80x30",    SW_VGA_C80x30,   M_VGA_C80x30 },
673146736Sdelphij		{ "VGA_80x50",    SW_VGA_C80x50,   M_VGA_C80x50 },
674146736Sdelphij		{ "VGA_80x60",    SW_VGA_C80x60,   M_VGA_C80x60 },
67548105Syokota#ifdef SW_VGA_C90x25
676146736Sdelphij		{ "VGA_90x25",    SW_VGA_C90x25,   M_VGA_C90x25 },
677146736Sdelphij		{ "VGA_90x30",    SW_VGA_C90x30,   M_VGA_C90x30 },
678146736Sdelphij		{ "VGA_90x43",    SW_VGA_C90x43,   M_VGA_C90x43 },
679146736Sdelphij		{ "VGA_90x50",    SW_VGA_C90x50,   M_VGA_C90x50 },
680146736Sdelphij		{ "VGA_90x60",    SW_VGA_C90x60,   M_VGA_C90x60 },
68148105Syokota#endif
682146736Sdelphij		{ "VGA_320x200",	SW_VGA_CG320,	M_CG320 },
683146736Sdelphij		{ "EGA_80x25",		SW_ENH_C80x25,	M_ENH_C80x25 },
684146736Sdelphij		{ "EGA_80x43",		SW_ENH_C80x43,	M_ENH_C80x43 },
685146736Sdelphij		{ "VESA_132x25",	SW_VESA_C132x25,M_VESA_C132x25 },
686146736Sdelphij		{ "VESA_132x43",	SW_VESA_C132x43,M_VESA_C132x43 },
687146736Sdelphij		{ "VESA_132x50",	SW_VESA_C132x50,M_VESA_C132x50 },
688146736Sdelphij		{ "VESA_132x60",	SW_VESA_C132x60,M_VESA_C132x60 },
689146736Sdelphij		{ "VESA_800x600",	SW_VESA_800x600,M_VESA_800x600 },
690146736Sdelphij		{ NULL, 0, 0 },
69139592Syokota	};
692146736Sdelphij
693146736Sdelphij	int new_mode_num = 0;
69442605Smjacob	unsigned long mode = 0;
69548105Syokota	int cur_mode;
69648105Syokota	int ioerr;
69739287Ssos	int size[3];
69839592Syokota	int i;
6992089Ssos
70048105Syokota	if (ioctl(0, CONS_GET, &cur_mode) < 0)
70148105Syokota		err(1, "cannot get the current video mode");
702146736Sdelphij
703146736Sdelphij	/*
704146736Sdelphij	 * Parse the video mode argument...
705146736Sdelphij	 */
706146736Sdelphij
707146736Sdelphij	if (*mode_index < argc) {
708146736Sdelphij		if (!strncmp(argv[*mode_index], "MODE_", 5)) {
709146736Sdelphij			if (!isdigit(argv[*mode_index][5]))
710146736Sdelphij				errx(1, "invalid video mode number");
711146736Sdelphij
712146736Sdelphij			new_mode_num = atoi(&argv[*mode_index][5]);
713146736Sdelphij		} else {
714146736Sdelphij			for (i = 0; modes[i].name != NULL; ++i) {
715146736Sdelphij				if (!strcmp(argv[*mode_index], modes[i].name)) {
716146736Sdelphij					mode = modes[i].mode;
717146736Sdelphij					new_mode_num = modes[i].mode_num;
718146736Sdelphij					break;
719146736Sdelphij				}
72039592Syokota			}
721146736Sdelphij
722146736Sdelphij			if (modes[i].name == NULL)
723146736Sdelphij				return EXIT_FAILURE;
724146736Sdelphij			if (ioctl(0, mode, NULL) < 0) {
725146736Sdelphij				warn("cannot set videomode");
726146736Sdelphij				return EXIT_FAILURE;
727146736Sdelphij			}
72839592Syokota		}
729146736Sdelphij
730146736Sdelphij		/*
731146736Sdelphij		 * Collect enough information about the new video mode...
732146736Sdelphij		 */
733146736Sdelphij
734146736Sdelphij		new_mode_info.vi_mode = new_mode_num;
735146736Sdelphij
736146736Sdelphij		if (ioctl(0, CONS_MODEINFO, &new_mode_info) == -1) {
737146736Sdelphij			revert();
738146736Sdelphij			errc(1, errno, "obtaining new video mode parameters");
739120201Seivind		}
740146736Sdelphij
741146736Sdelphij		if (mode == 0) {
742146736Sdelphij			if (new_mode_num >= M_VESA_BASE)
743146736Sdelphij				mode = _IO('V', new_mode_num - M_VESA_BASE);
744146736Sdelphij			else
745146736Sdelphij				mode = _IO('S', new_mode_num);
746146736Sdelphij		}
747146736Sdelphij
748146736Sdelphij		/*
749146736Sdelphij		 * Try setting the new mode.
750146736Sdelphij		 */
751146736Sdelphij
752146736Sdelphij		if (ioctl(0, mode, NULL) == -1) {
753146736Sdelphij			revert();
754146736Sdelphij			errc(1, errno, "setting video mode");
755146736Sdelphij		}
756146736Sdelphij
757146736Sdelphij		/*
758146736Sdelphij		 * For raster modes it's not enough to just set the mode.
759146736Sdelphij		 * We also need to explicitly set the raster mode.
760146736Sdelphij		 */
761146736Sdelphij
762146736Sdelphij		if (new_mode_info.vi_flags & V_INFO_GRAPHICS) {
763146736Sdelphij			/* font size */
764146736Sdelphij
765146736Sdelphij			if (font_height == 0)
766146736Sdelphij				font_height = cur_info.console_info.font_size;
767146736Sdelphij
768146736Sdelphij			size[2] = font_height;
769146736Sdelphij
770146736Sdelphij			/* adjust columns */
771146736Sdelphij
772146736Sdelphij			if ((vesa_cols * 8 > new_mode_info.vi_width) ||
773146736Sdelphij			    (vesa_cols <= 0)) {
774146736Sdelphij				size[0] = new_mode_info.vi_width / 8;
77571642Ssobomax			} else {
77671642Ssobomax				size[0] = vesa_cols;
77771642Ssobomax			}
778146736Sdelphij
779146736Sdelphij			/* adjust rows */
780146736Sdelphij
781146736Sdelphij			if ((vesa_rows * font_height > new_mode_info.vi_height) ||
782146736Sdelphij			    (vesa_rows <= 0)) {
783146736Sdelphij				size[1] = new_mode_info.vi_height /
784146736Sdelphij					  font_height;
78571642Ssobomax			} else {
78671642Ssobomax				size[1] = vesa_rows;
78771642Ssobomax			}
788146736Sdelphij
789146736Sdelphij			/* set raster mode */
790146736Sdelphij
79148105Syokota			if (ioctl(0, KDRASTER, size)) {
79248105Syokota				ioerr = errno;
79348105Syokota				if (cur_mode >= M_VESA_BASE)
79480148Syokota					ioctl(0,
79580148Syokota					    _IO('V', cur_mode - M_VESA_BASE),
79680148Syokota					    NULL);
79748105Syokota				else
79848105Syokota					ioctl(0, _IO('S', cur_mode), NULL);
799146736Sdelphij				revert();
80048105Syokota				warnc(ioerr, "cannot activate raster display");
801120201Seivind				return EXIT_FAILURE;
80248105Syokota			}
80339287Ssos		}
804146736Sdelphij
805146736Sdelphij		video_mode_changed = 1;
806146736Sdelphij
807146736Sdelphij		(*mode_index)++;
8082089Ssos	}
809120201Seivind	return EXIT_SUCCESS;
8102089Ssos}
8118857Srgrimes
812146736Sdelphij
813146736Sdelphij/*
814146736Sdelphij * Return the number for a specified color name.
815146736Sdelphij */
816146736Sdelphij
817140159Sdelphijstatic int
8182089Ssosget_color_number(char *color)
8192089Ssos{
8202089Ssos	int i;
8212089Ssos
822146736Sdelphij	for (i=0; i<16; i++) {
8232089Ssos		if (!strcmp(color, legal_colors[i]))
8242089Ssos			return i;
825146736Sdelphij	}
8262089Ssos	return -1;
8272089Ssos}
8282089Ssos
829146736Sdelphij
830146736Sdelphij/*
831146736Sdelphij * Get normal text and background colors.
832146736Sdelphij */
833146736Sdelphij
834140159Sdelphijstatic void
835146736Sdelphijget_normal_colors(int argc, char **argv, int *_index)
8362089Ssos{
8372089Ssos	int color;
8382089Ssos
839140159Sdelphij	if (*_index < argc && (color = get_color_number(argv[*_index])) != -1) {
840140159Sdelphij		(*_index)++;
841146241Snyan		fprintf(stderr, "\033[=%dF", color);
842150246Srodrigc		normal_fore_color=color;
843150246Srodrigc		colors_changed = 1;
844140159Sdelphij		if (*_index < argc
845140159Sdelphij		    && (color = get_color_number(argv[*_index])) != -1
8462089Ssos		    && color < 8) {
847140159Sdelphij			(*_index)++;
848146241Snyan			fprintf(stderr, "\033[=%dG", color);
849150246Srodrigc			normal_back_color=color;
8502089Ssos		}
8512089Ssos	}
8522089Ssos}
8532089Ssos
854146736Sdelphij
855146736Sdelphij/*
856146736Sdelphij * Get reverse text and background colors.
857146736Sdelphij */
858146736Sdelphij
859140159Sdelphijstatic void
860146736Sdelphijget_reverse_colors(int argc, char **argv, int *_index)
8612089Ssos{
8622089Ssos	int color;
8632089Ssos
864140159Sdelphij	if ((color = get_color_number(argv[*(_index)-1])) != -1) {
865146241Snyan		fprintf(stderr, "\033[=%dH", color);
866150246Srodrigc		revers_fore_color=color;
867150246Srodrigc		colors_changed = 1;
868140159Sdelphij		if (*_index < argc
869140159Sdelphij		    && (color = get_color_number(argv[*_index])) != -1
8702089Ssos		    && color < 8) {
871140159Sdelphij			(*_index)++;
872146241Snyan			fprintf(stderr, "\033[=%dI", color);
873150246Srodrigc			revers_back_color=color;
8742089Ssos		}
8752089Ssos	}
8762089Ssos}
8772089Ssos
878146736Sdelphij
879146736Sdelphij/*
880146736Sdelphij * Set normal and reverse foreground and background colors.
881146736Sdelphij */
882146736Sdelphij
883140159Sdelphijstatic void
884146736Sdelphijset_colors(void)
885146736Sdelphij{
886146736Sdelphij	fprintf(stderr, "\033[=%dF", normal_fore_color);
887146736Sdelphij	fprintf(stderr, "\033[=%dG", normal_back_color);
888146736Sdelphij	fprintf(stderr, "\033[=%dH", revers_fore_color);
889146736Sdelphij	fprintf(stderr, "\033[=%dI", revers_back_color);
890146736Sdelphij}
891146736Sdelphij
892146736Sdelphij
893146736Sdelphij/*
894146736Sdelphij * Switch to virtual terminal #arg.
895146736Sdelphij */
896146736Sdelphij
897146736Sdelphijstatic void
89823457Sbrianset_console(char *arg)
89923457Sbrian{
90023457Sbrian	int n;
90123457Sbrian
902146736Sdelphij	if(!arg || strspn(arg,"0123456789") != strlen(arg)) {
903146736Sdelphij		revert();
904146736Sdelphij		errx(1, "bad console number");
90523457Sbrian	}
90623457Sbrian
90723457Sbrian	n = atoi(arg);
908146736Sdelphij
90951393Syokota	if (n < 1 || n > 16) {
910146736Sdelphij		revert();
911146736Sdelphij		errx(1, "console number out of range");
912162671Sru	} else if (ioctl(0, VT_ACTIVATE, n) == -1) {
913146736Sdelphij		revert();
914146736Sdelphij		errc(1, errno, "switching vty");
915146736Sdelphij	}
91623457Sbrian}
91723457Sbrian
918146736Sdelphij
919146736Sdelphij/*
920146736Sdelphij * Sets the border color.
921146736Sdelphij */
922146736Sdelphij
923140159Sdelphijstatic void
9242089Ssosset_border_color(char *arg)
9252089Ssos{
9262089Ssos	int color;
9272089Ssos
9282089Ssos	if ((color = get_color_number(arg)) != -1) {
929146241Snyan		fprintf(stderr, "\033[=%dA", color);
9302089Ssos	}
9312089Ssos	else
9328857Srgrimes		usage();
9332089Ssos}
9342089Ssos
935140159Sdelphijstatic void
93655849Syokotaset_mouse_char(char *arg)
93755849Syokota{
93855849Syokota	struct mouse_info mouse;
93955849Syokota	long l;
94055849Syokota
94155849Syokota	l = strtol(arg, NULL, 0);
942146736Sdelphij
94375788Sache	if ((l < 0) || (l > UCHAR_MAX - 3)) {
944146736Sdelphij		revert();
94575788Sache		warnx("argument to -M must be 0 through %d", UCHAR_MAX - 3);
94655849Syokota		return;
94755849Syokota	}
948146736Sdelphij
94955849Syokota	mouse.operation = MOUSE_MOUSECHAR;
95055849Syokota	mouse.u.mouse_char = (int)l;
951146736Sdelphij
952146736Sdelphij	if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) {
953146736Sdelphij		revert();
954146736Sdelphij		errc(1, errno, "setting mouse character");
955146736Sdelphij	}
95655849Syokota}
95755849Syokota
958146736Sdelphij
959146736Sdelphij/*
960146736Sdelphij * Show/hide the mouse.
961146736Sdelphij */
962146736Sdelphij
963140159Sdelphijstatic void
96416565Ssosset_mouse(char *arg)
96516565Ssos{
96616565Ssos	struct mouse_info mouse;
96716565Ssos
968146736Sdelphij	if (!strcmp(arg, "on")) {
96916565Ssos		mouse.operation = MOUSE_SHOW;
970146736Sdelphij	} else if (!strcmp(arg, "off")) {
97116565Ssos		mouse.operation = MOUSE_HIDE;
972146736Sdelphij	} else {
973146736Sdelphij		revert();
974146736Sdelphij		errx(1, "argument to -m must be either on or off");
97516565Ssos	}
976146736Sdelphij
977146736Sdelphij	if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) {
978146736Sdelphij		revert();
979146736Sdelphij		errc(1, errno, "%sing the mouse",
980146736Sdelphij		     mouse.operation == MOUSE_SHOW ? "show" : "hid");
981146736Sdelphij	}
98216565Ssos}
98316565Ssos
984146736Sdelphij
985140159Sdelphijstatic void
98699705Sddset_lockswitch(char *arg)
98799705Sdd{
98899705Sdd	int data;
98999705Sdd
990146736Sdelphij	if (!strcmp(arg, "off")) {
99199705Sdd		data = 0x01;
992146736Sdelphij	} else if (!strcmp(arg, "on")) {
99399705Sdd		data = 0x02;
994146736Sdelphij	} else {
995146736Sdelphij		revert();
996146736Sdelphij		errx(1, "argument to -S must be either on or off");
99799705Sdd	}
998146736Sdelphij
999146736Sdelphij	if (ioctl(0, VT_LOCKSWITCH, &data) == -1) {
1000146736Sdelphij		revert();
1001146736Sdelphij		errc(1, errno, "turning %s vty switching",
1002146736Sdelphij		     data == 0x01 ? "off" : "on");
1003146736Sdelphij	}
100499705Sdd}
100599705Sdd
1006146736Sdelphij
1007146736Sdelphij/*
1008146736Sdelphij * Return the adapter name for a specified type.
1009146736Sdelphij */
1010146736Sdelphij
1011140159Sdelphijstatic const char
101239287Ssos*adapter_name(int type)
101339287Ssos{
101439287Ssos    static struct {
101539287Ssos	int type;
1016140159Sdelphij	const char *name;
101739287Ssos    } names[] = {
101839287Ssos	{ KD_MONO,	"MDA" },
101939287Ssos	{ KD_HERCULES,	"Hercules" },
102039287Ssos	{ KD_CGA,	"CGA" },
102139287Ssos	{ KD_EGA,	"EGA" },
102239287Ssos	{ KD_VGA,	"VGA" },
102339287Ssos	{ KD_PC98,	"PC-98xx" },
102448105Syokota	{ KD_TGA,	"TGA" },
102539287Ssos	{ -1,		"Unknown" },
102639287Ssos    };
1027146736Sdelphij
102839287Ssos    int i;
102939287Ssos
103039287Ssos    for (i = 0; names[i].type != -1; ++i)
103139287Ssos	if (names[i].type == type)
103239287Ssos	    break;
103339287Ssos    return names[i].name;
103439287Ssos}
103539287Ssos
1036146736Sdelphij
1037146736Sdelphij/*
1038146736Sdelphij * Show graphics adapter information.
1039146736Sdelphij */
1040146736Sdelphij
1041140159Sdelphijstatic void
104239287Ssosshow_adapter_info(void)
104339287Ssos{
104442505Syokota	struct video_adapter_info ad;
104539287Ssos
104639287Ssos	ad.va_index = 0;
1047146736Sdelphij
1048146736Sdelphij	if (ioctl(0, CONS_ADPINFO, &ad) == -1) {
1049146736Sdelphij		revert();
1050146736Sdelphij		errc(1, errno, "obtaining adapter information");
105139287Ssos	}
105239287Ssos
105342505Syokota	printf("fb%d:\n", ad.va_index);
105442505Syokota	printf("    %.*s%d, type:%s%s (%d), flags:0x%x\n",
105542505Syokota	       (int)sizeof(ad.va_name), ad.va_name, ad.va_unit,
105639287Ssos	       (ad.va_flags & V_ADP_VESA) ? "VESA " : "",
105742505Syokota	       adapter_name(ad.va_type), ad.va_type, ad.va_flags);
105839287Ssos	printf("    initial mode:%d, current mode:%d, BIOS mode:%d\n",
105939287Ssos	       ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode);
1060140159Sdelphij	printf("    frame buffer window:0x%zx, buffer size:0x%zx\n",
106148105Syokota	       ad.va_window, ad.va_buffer_size);
1062140159Sdelphij	printf("    window size:0x%zx, origin:0x%x\n",
106348105Syokota	       ad.va_window_size, ad.va_window_orig);
106448105Syokota	printf("    display start address (%d, %d), scan line width:%d\n",
106548105Syokota	       ad.va_disp_start.x, ad.va_disp_start.y, ad.va_line_width);
1066140159Sdelphij	printf("    reserved:0x%zx\n", ad.va_unused0);
106739287Ssos}
106839287Ssos
1069146736Sdelphij
1070146736Sdelphij/*
1071146736Sdelphij * Show video mode information.
1072146736Sdelphij */
1073146736Sdelphij
1074140159Sdelphijstatic void
107539287Ssosshow_mode_info(void)
107639287Ssos{
1077205855Sjkim	char buf[80];
1078140159Sdelphij	struct video_info _info;
1079205855Sjkim	int c;
1080205855Sjkim	int mm;
108139287Ssos	int mode;
108239287Ssos
108339287Ssos	printf("    mode#     flags   type    size       "
108439287Ssos	       "font      window      linear buffer\n");
108539287Ssos	printf("---------------------------------------"
108639287Ssos	       "---------------------------------------\n");
1087146736Sdelphij
1088250509Seadler	for (mode = 0; mode <= M_VESA_MODE_MAX; ++mode) {
1089140159Sdelphij		_info.vi_mode = mode;
1090140159Sdelphij		if (ioctl(0, CONS_MODEINFO, &_info))
109139287Ssos			continue;
1092140159Sdelphij		if (_info.vi_mode != mode)
109348105Syokota			continue;
109439287Ssos
109539287Ssos		printf("%3d (0x%03x)", mode, mode);
1096140159Sdelphij    		printf(" 0x%08x", _info.vi_flags);
1097140159Sdelphij		if (_info.vi_flags & V_INFO_GRAPHICS) {
109839287Ssos			c = 'G';
1099146736Sdelphij
1100205855Sjkim			if (_info.vi_mem_model == V_INFO_MM_PLANAR)
1101205855Sjkim				snprintf(buf, sizeof(buf), "%dx%dx%d %d",
1102205855Sjkim				    _info.vi_width, _info.vi_height,
1103205855Sjkim				    _info.vi_depth, _info.vi_planes);
1104205855Sjkim			else {
1105205855Sjkim				switch (_info.vi_mem_model) {
1106205855Sjkim				case V_INFO_MM_PACKED:
1107205855Sjkim					mm = 'P';
1108205855Sjkim					break;
1109205855Sjkim				case V_INFO_MM_DIRECT:
1110205855Sjkim					mm = 'D';
1111205855Sjkim					break;
1112205855Sjkim				case V_INFO_MM_CGA:
1113205855Sjkim					mm = 'C';
1114205855Sjkim					break;
1115205855Sjkim				case V_INFO_MM_HGC:
1116205855Sjkim					mm = 'H';
1117205855Sjkim					break;
1118205855Sjkim				case V_INFO_MM_VGAX:
1119205855Sjkim					mm = 'V';
1120205855Sjkim					break;
1121205855Sjkim				default:
1122205855Sjkim					mm = ' ';
1123205855Sjkim					break;
1124205855Sjkim				}
1125205855Sjkim				snprintf(buf, sizeof(buf), "%dx%dx%d %c",
1126205855Sjkim				    _info.vi_width, _info.vi_height,
1127205855Sjkim				    _info.vi_depth, mm);
1128205855Sjkim			}
112939287Ssos		} else {
113039287Ssos			c = 'T';
1131146736Sdelphij
113239287Ssos			snprintf(buf, sizeof(buf), "%dx%d",
1133140159Sdelphij				 _info.vi_width, _info.vi_height);
113439287Ssos		}
1135146736Sdelphij
113639287Ssos		printf(" %c %-15s", c, buf);
113739287Ssos		snprintf(buf, sizeof(buf), "%dx%d",
1138140159Sdelphij			 _info.vi_cwidth, _info.vi_cheight);
113939287Ssos		printf(" %-5s", buf);
1140140159Sdelphij    		printf(" 0x%05zx %2dk %2dk",
1141140159Sdelphij		       _info.vi_window, (int)_info.vi_window_size/1024,
1142140159Sdelphij		       (int)_info.vi_window_gran/1024);
1143140159Sdelphij    		printf(" 0x%08zx %dk\n",
1144140159Sdelphij		       _info.vi_buffer, (int)_info.vi_buffer_size/1024);
114539287Ssos	}
114639287Ssos}
114739287Ssos
1148146736Sdelphij
1149140159Sdelphijstatic void
115039287Ssosshow_info(char *arg)
115139287Ssos{
1152146736Sdelphij	if (!strcmp(arg, "adapter")) {
115339287Ssos		show_adapter_info();
1154146736Sdelphij	} else if (!strcmp(arg, "mode")) {
115539287Ssos		show_mode_info();
1156146736Sdelphij	} else {
1157146736Sdelphij		revert();
1158146736Sdelphij		errx(1, "argument to -i must be either adapter or mode");
115939287Ssos	}
116039287Ssos}
116139287Ssos
1162146736Sdelphij
1163140159Sdelphijstatic void
1164140159Sdelphijtest_frame(void)
11652089Ssos{
1166146237Snyan	int i, cur_mode, fore;
11672089Ssos
1168146237Snyan	fore = 15;
1169146237Snyan
1170146237Snyan	if (ioctl(0, CONS_GET, &cur_mode) < 0)
1171146237Snyan		err(1, "must be on a virtual console");
1172146237Snyan	switch (cur_mode) {
1173146237Snyan	case M_PC98_80x25:
1174146237Snyan	case M_PC98_80x30:
1175146237Snyan		fore = 7;
1176146237Snyan		break;
1177146237Snyan	}
1178146237Snyan
1179146241Snyan	fprintf(stdout, "\033[=0G\n\n");
11802089Ssos	for (i=0; i<8; i++) {
1181146241Snyan		fprintf(stdout, "\033[=%dF\033[=0G        %2d \033[=%dF%-16s"
1182146241Snyan				"\033[=%dF\033[=0G        %2d \033[=%dF%-16s        "
1183146241Snyan				"\033[=%dF %2d \033[=%dGBACKGROUND\033[=0G\n",
1184146237Snyan			fore, i, i, legal_colors[i],
1185146237Snyan			fore, i+8, i+8, legal_colors[i+8],
1186146237Snyan			fore, i, i);
11872089Ssos	}
1188146241Snyan	fprintf(stdout, "\033[=%dF\033[=%dG\033[=%dH\033[=%dI\n",
11898857Srgrimes		info.mv_norm.fore, info.mv_norm.back,
11902089Ssos		info.mv_rev.fore, info.mv_rev.back);
11912089Ssos}
11922089Ssos
1193146736Sdelphij
119476845Ssobomax/*
119576845Ssobomax * Snapshot the video memory of that terminal, using the CONS_SCRSHOT
119676845Ssobomax * ioctl, and writes the results to stdout either in the special
119776845Ssobomax * binary format (see manual page for details), or in the plain
119876845Ssobomax * text format.
119976845Ssobomax */
1200146736Sdelphij
1201140159Sdelphijstatic void
1202102111Ssobomaxdump_screen(int mode, int opt)
120376845Ssobomax{
120476845Ssobomax	scrshot_t shot;
1205140159Sdelphij	vid_info_t _info;
120676845Ssobomax
1207140159Sdelphij	_info.size = sizeof(_info);
1208146736Sdelphij
1209140159Sdelphij	if (ioctl(0, CONS_GETINFO, &_info) == -1) {
1210146736Sdelphij		revert();
1211146736Sdelphij		errc(1, errno, "obtaining current video mode parameters");
121276845Ssobomax		return;
121376845Ssobomax	}
121476845Ssobomax
1215102111Ssobomax	shot.x = shot.y = 0;
1216140159Sdelphij	shot.xsize = _info.mv_csz;
1217140159Sdelphij	shot.ysize = _info.mv_rsz;
1218102111Ssobomax	if (opt == DUMP_ALL)
1219140159Sdelphij		shot.ysize += _info.mv_hsz;
1220102111Ssobomax
1221102111Ssobomax	shot.buf = alloca(shot.xsize * shot.ysize * sizeof(u_int16_t));
122276845Ssobomax	if (shot.buf == NULL) {
1223146736Sdelphij		revert();
1224146736Sdelphij		errx(1, "failed to allocate memory for dump");
122576845Ssobomax	}
122676845Ssobomax
122776845Ssobomax	if (ioctl(0, CONS_SCRSHOT, &shot) == -1) {
1228146736Sdelphij		revert();
1229146736Sdelphij		errc(1, errno, "dumping screen");
123076845Ssobomax	}
123176845Ssobomax
1232102111Ssobomax	if (mode == DUMP_FMT_RAW) {
123376845Ssobomax		printf("SCRSHOT_%c%c%c%c", DUMP_FMT_REV, 2,
123476845Ssobomax		       shot.xsize, shot.ysize);
1235146736Sdelphij
123676845Ssobomax		fflush(stdout);
123776845Ssobomax
1238146736Sdelphij		write(STDOUT_FILENO, shot.buf,
1239146736Sdelphij		      shot.xsize * shot.ysize * sizeof(u_int16_t));
124076845Ssobomax	} else {
124176845Ssobomax		char *line;
124276845Ssobomax		int x, y;
124376845Ssobomax		u_int16_t ch;
124476845Ssobomax
124576845Ssobomax		line = alloca(shot.xsize + 1);
1246146736Sdelphij
124776845Ssobomax		if (line == NULL) {
1248146736Sdelphij			revert();
1249146736Sdelphij			errx(1, "failed to allocate memory for line buffer");
125076845Ssobomax		}
125176845Ssobomax
125276845Ssobomax		for (y = 0; y < shot.ysize; y++) {
125376845Ssobomax			for (x = 0; x < shot.xsize; x++) {
125476845Ssobomax				ch = shot.buf[x + (y * shot.xsize)];
125576845Ssobomax				ch &= 0xff;
1256146736Sdelphij
125776845Ssobomax				if (isprint(ch) == 0)
125876845Ssobomax					ch = ' ';
1259146736Sdelphij
126076845Ssobomax				line[x] = (char)ch;
126176845Ssobomax			}
126276845Ssobomax
126376845Ssobomax			/* Trim trailing spaces */
1264146736Sdelphij
126576845Ssobomax			do {
126676845Ssobomax				line[x--] = '\0';
126776845Ssobomax			} while (line[x] == ' ' && x != 0);
126876845Ssobomax
126976845Ssobomax			puts(line);
127076845Ssobomax		}
1271146736Sdelphij
127276845Ssobomax		fflush(stdout);
127376845Ssobomax	}
127476845Ssobomax}
127576845Ssobomax
1276146736Sdelphij
1277146736Sdelphij/*
1278146736Sdelphij * Set the console history buffer size.
1279146736Sdelphij */
1280146736Sdelphij
1281140159Sdelphijstatic void
128277329Sdesset_history(char *opt)
128377329Sdes{
128477329Sdes	int size;
128577329Sdes
128677329Sdes	size = atoi(opt);
1287146736Sdelphij
128877329Sdes	if ((*opt == '\0') || size < 0) {
1289146736Sdelphij		revert();
1290146736Sdelphij		errx(1, "argument must be a positive number");
129177329Sdes	}
1292146736Sdelphij
1293146736Sdelphij	if (ioctl(0, CONS_HISTORY, &size) == -1) {
1294146736Sdelphij		revert();
1295146736Sdelphij		errc(1, errno, "setting history buffer size");
1296146736Sdelphij	}
129777329Sdes}
129877329Sdes
1299146736Sdelphij
1300146736Sdelphij/*
1301146736Sdelphij * Clear the console history buffer.
1302146736Sdelphij */
1303146736Sdelphij
1304140159Sdelphijstatic void
1305140159Sdelphijclear_history(void)
130677329Sdes{
1307146736Sdelphij	if (ioctl(0, CONS_CLRHIST) == -1) {
1308146736Sdelphij		revert();
1309146736Sdelphij		errc(1, errno, "clearing history buffer");
1310146736Sdelphij	}
131177329Sdes}
131277329Sdes
1313199174Sedstatic void
1314199174Sedset_terminal_mode(char *arg)
1315199174Sed{
1316146736Sdelphij
1317199174Sed	if (strcmp(arg, "xterm") == 0)
1318199174Sed		fprintf(stderr, "\033[=T");
1319199174Sed	else if (strcmp(arg, "cons25") == 0)
1320199174Sed		fprintf(stderr, "\033[=1T");
1321199174Sed}
1322199174Sed
1323199174Sed
132423457Sbrianint
13252089Ssosmain(int argc, char **argv)
13262089Ssos{
1327237777Sache	char    *font, *type, *termmode;
1328267540Sray	const char *opts;
1329102111Ssobomax	int	dumpmod, dumpopt, opt;
1330120201Seivind	int	reterr;
13312089Ssos
1332267540Sray	vt4_mode = is_vt4();
1333267540Sray
1334146736Sdelphij	init();
1335146736Sdelphij
13362089Ssos	info.size = sizeof(info);
1337146736Sdelphij
1338146736Sdelphij	if (ioctl(0, CONS_GETINFO, &info) == -1)
133930764Scharnier		err(1, "must be on a virtual console");
1340102111Ssobomax	dumpmod = 0;
1341102111Ssobomax	dumpopt = DUMP_FBF;
1342237777Sache	termmode = NULL;
1343267540Sray	if (vt4_mode)
1344273921Sdumbbell		opts = "b:Cc:fg:h:Hi:M:m:pPr:S:s:T:t:x";
1345267540Sray	else
1346286291Semaste		opts = "b:Cc:dfg:h:Hi:l:LM:m:pPr:S:s:T:t:x";
1347267540Sray
1348267540Sray	while ((opt = getopt(argc, argv, opts)) != -1)
13492089Ssos		switch(opt) {
135077329Sdes		case 'b':
135177329Sdes			set_border_color(optarg);
135277329Sdes			break;
135377329Sdes		case 'C':
135477329Sdes			clear_history();
135577329Sdes			break;
135677329Sdes		case 'c':
135777329Sdes			set_cursor_type(optarg);
135877329Sdes			break;
135977329Sdes		case 'd':
1360267540Sray			if (vt4_mode)
1361267540Sray				break;
136277329Sdes			print_scrnmap();
136377329Sdes			break;
136477329Sdes		case 'f':
1365273921Sdumbbell			optarg = nextarg(argc, argv, &optind, 'f', 0);
1366273921Sdumbbell			if (optarg != NULL) {
1367273921Sdumbbell				font = nextarg(argc, argv, &optind, 'f', 0);
1368146736Sdelphij
1369273921Sdumbbell				if (font == NULL) {
1370273921Sdumbbell					type = NULL;
1371273921Sdumbbell					font = optarg;
1372273921Sdumbbell				} else
1373273921Sdumbbell					type = optarg;
1374273921Sdumbbell
1375273921Sdumbbell				load_font(type, font);
1376273921Sdumbbell			} else {
1377273921Sdumbbell				if (!vt4_mode)
1378273921Sdumbbell					usage(); /* Switch syscons to ROM? */
1379273921Sdumbbell
1380273921Sdumbbell				load_default_vt4font();
138177329Sdes			}
138277329Sdes			break;
138377329Sdes		case 'g':
1384146736Sdelphij			if (sscanf(optarg, "%dx%d",
1385146736Sdelphij			    &vesa_cols, &vesa_rows) != 2) {
1386146736Sdelphij				revert();
138777329Sdes				warnx("incorrect geometry: %s", optarg);
13882089Ssos				usage();
138977329Sdes			}
1390146736Sdelphij                	break;
139177329Sdes		case 'h':
139277329Sdes			set_history(optarg);
139377329Sdes			break;
1394102111Ssobomax		case 'H':
1395102111Ssobomax			dumpopt = DUMP_ALL;
1396102111Ssobomax			break;
139777329Sdes		case 'i':
139877329Sdes			show_info(optarg);
139977329Sdes			break;
140077329Sdes		case 'l':
1401267540Sray			if (vt4_mode)
1402267540Sray				break;
140377329Sdes			load_scrnmap(optarg);
140477329Sdes			break;
140577329Sdes		case 'L':
1406267540Sray			if (vt4_mode)
1407267540Sray				break;
140877329Sdes			load_default_scrnmap();
140977329Sdes			break;
141077329Sdes		case 'M':
141177329Sdes			set_mouse_char(optarg);
141277329Sdes			break;
141377329Sdes		case 'm':
141477329Sdes			set_mouse(optarg);
141577329Sdes			break;
141677329Sdes		case 'p':
1417102111Ssobomax			dumpmod = DUMP_FMT_RAW;
141877329Sdes			break;
141977329Sdes		case 'P':
1420102111Ssobomax			dumpmod = DUMP_FMT_TXT;
142177329Sdes			break;
142277329Sdes		case 'r':
1423146736Sdelphij			get_reverse_colors(argc, argv, &optind);
142477329Sdes			break;
142599705Sdd		case 'S':
142699705Sdd			set_lockswitch(optarg);
142799705Sdd			break;
142877329Sdes		case 's':
142977329Sdes			set_console(optarg);
143077329Sdes			break;
1431199174Sed		case 'T':
1432237777Sache			if (strcmp(optarg, "xterm") != 0 &&
1433237777Sache			    strcmp(optarg, "cons25") != 0)
1434237777Sache				usage();
1435237777Sache			termmode = optarg;
1436199174Sed			break;
143777329Sdes		case 't':
143877329Sdes			set_screensaver_timeout(optarg);
143977329Sdes			break;
144077329Sdes		case 'x':
144177329Sdes			hex = 1;
144277329Sdes			break;
144377329Sdes		default:
144477329Sdes			usage();
14452089Ssos		}
1446146736Sdelphij
1447102111Ssobomax	if (dumpmod != 0)
1448102111Ssobomax		dump_screen(dumpmod, dumpopt);
1449120201Seivind	reterr = video_mode(argc, argv, &optind);
1450146736Sdelphij	get_normal_colors(argc, argv, &optind);
1451146736Sdelphij
14522089Ssos	if (optind < argc && !strcmp(argv[optind], "show")) {
14532089Ssos		test_frame();
14542089Ssos		optind++;
14552089Ssos	}
1456146736Sdelphij
1457146736Sdelphij	video_mode(argc, argv, &optind);
1458237777Sache	if (termmode != NULL)
1459237777Sache		set_terminal_mode(termmode);
1460146736Sdelphij
1461146736Sdelphij	get_normal_colors(argc, argv, &optind);
1462146736Sdelphij
1463146736Sdelphij	if (colors_changed || video_mode_changed) {
1464146736Sdelphij		if (!(new_mode_info.vi_flags & V_INFO_GRAPHICS)) {
1465146736Sdelphij			if ((normal_back_color < 8) && (revers_back_color < 8)) {
1466146736Sdelphij				set_colors();
1467146736Sdelphij			} else {
1468146736Sdelphij				revert();
1469146736Sdelphij				errx(1, "bg color for text modes must be < 8");
1470146736Sdelphij			}
1471146736Sdelphij		} else {
1472146736Sdelphij			set_colors();
1473146736Sdelphij		}
1474146736Sdelphij	}
1475146736Sdelphij
147630764Scharnier	if ((optind != argc) || (argc == 1))
14772089Ssos		usage();
1478120201Seivind	return reterr;
14792089Ssos}
14802089Ssos
1481