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: stable/10/usr.sbin/vidcontrol/vidcontrol.c 313552 2017-02-10 15:02:56Z 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
396313552Semaste	if ((t = malloc(sizeof *t * nmappings)) == NULL) {
397313552Semaste		warn("malloc");
398313552Semaste		return (NULL);
399313552Semaste	}
400267540Sray
401267540Sray	if (fread(t, sizeof *t * nmappings, 1, f) != 1) {
402313552Semaste		warn("read mappings");
403313552Semaste		free(t);
404313552Semaste		return (NULL);
405267540Sray	}
406267540Sray
407267540Sray	for (i = 0; i < nmappings; i++) {
408267540Sray		t[i].src = be32toh(t[i].src);
409267540Sray		t[i].dst = be16toh(t[i].dst);
410267540Sray		t[i].len = be16toh(t[i].len);
411267540Sray	}
412267540Sray
413267540Sray	return (t);
414267540Sray}
415267540Sray
416273921Sdumbbell/*
417273921Sdumbbell * Set the default vt font.
418273921Sdumbbell */
419273921Sdumbbell
420273921Sdumbbellstatic void
421273921Sdumbbellload_default_vt4font(void)
422273921Sdumbbell{
423273921Sdumbbell	if (ioctl(0, PIO_VFONT_DEFAULT) == -1) {
424273921Sdumbbell		revert();
425273921Sdumbbell		errc(1, errno, "loading default vt font");
426273921Sdumbbell	}
427273921Sdumbbell}
428273921Sdumbbell
429313552Semastestatic void
430267540Srayload_vt4font(FILE *f)
431267540Sray{
432267540Sray	struct vt4font_header fh;
433267540Sray	static vfnt_t vfnt;
434267540Sray	size_t glyphsize;
435267540Sray	unsigned int i;
436267540Sray
437267540Sray	if (fread(&fh, sizeof fh, 1, f) != 1) {
438313552Semaste		warn("read file_header");
439313552Semaste		return;
440267540Sray	}
441267540Sray
442267540Sray	if (memcmp(fh.magic, "VFNT0002", 8) != 0) {
443313552Semaste		warnx("bad magic in font file\n");
444313552Semaste		return;
445267540Sray	}
446267540Sray
447267540Sray	for (i = 0; i < VFNT_MAPS; i++)
448267540Sray		vfnt.map_count[i] = be32toh(fh.map_count[i]);
449267540Sray	vfnt.glyph_count = be32toh(fh.glyph_count);
450267540Sray	vfnt.width = fh.width;
451267540Sray	vfnt.height = fh.height;
452267540Sray
453267540Sray	glyphsize = howmany(vfnt.width, 8) * vfnt.height * vfnt.glyph_count;
454313552Semaste	if ((vfnt.glyphs = malloc(glyphsize)) == NULL) {
455313552Semaste		warn("malloc");
456313552Semaste		return;
457313552Semaste	}
458267540Sray
459267540Sray	if (fread(vfnt.glyphs, glyphsize, 1, f) != 1) {
460313552Semaste		warn("read glyphs");
461313552Semaste		free(vfnt.glyphs);
462313552Semaste		return;
463267540Sray	}
464267540Sray
465267540Sray	for (i = 0; i < VFNT_MAPS; i++)
466267540Sray		vfnt.map[i] = load_vt4mappingtable(vfnt.map_count[i], f);
467267540Sray
468313552Semaste	if (ioctl(STDIN_FILENO, PIO_VFONT, &vfnt) == -1)
469313552Semaste		warn("PIO_VFONT");
470313552Semaste
471313552Semaste	for (i = 0; i < VFNT_MAPS; i++)
472313552Semaste		free(vfnt.map[i]);
473313552Semaste	free(vfnt.glyphs);
474267540Sray}
475267540Sray
476146736Sdelphij/*
477146736Sdelphij * Load a font from file and set it.
478146736Sdelphij */
479146736Sdelphij
480140159Sdelphijstatic void
481140159Sdelphijload_font(const char *type, const char *filename)
4822089Ssos{
48392460Ssobomax	FILE	*fd;
48475344Ssobomax	int	h, i, size, w;
48575344Ssobomax	unsigned long io = 0;	/* silence stupid gcc(1) in the Wall mode */
48692460Ssobomax	char	*name, *fontmap, size_sufx[6];
487140159Sdelphij	const char	*a[] = {"", FONT_PATH, NULL};
488267540Sray	const char	*vt4a[] = {"", VT_FONT_PATH, NULL};
489140159Sdelphij	const char	*b[] = {filename, NULL};
490140159Sdelphij	const char	*c[] = {"", size_sufx, NULL};
491140159Sdelphij	const char	*d[] = {"", ".fnt", NULL};
492140159Sdelphij	vid_info_t _info;
4932089Ssos
49475344Ssobomax	struct sizeinfo {
49575344Ssobomax		int w;
49675344Ssobomax		int h;
49775344Ssobomax		unsigned long io;
49875344Ssobomax	} sizes[] = {{8, 16, PIO_FONT8x16},
49975344Ssobomax		     {8, 14, PIO_FONT8x14},
50075344Ssobomax		     {8,  8,  PIO_FONT8x8},
50175344Ssobomax		     {0,  0,            0}};
50275344Ssobomax
503267540Sray	if (vt4_mode) {
504267540Sray		size_sufx[0] = '\0';
505267540Sray	} else {
506267540Sray		_info.size = sizeof(_info);
507267540Sray		if (ioctl(0, CONS_GETINFO, &_info) == -1) {
508267540Sray			revert();
509267540Sray			warn("failed to obtain current video mode parameters");
510267540Sray			return;
511267540Sray		}
512267540Sray
513267540Sray		snprintf(size_sufx, sizeof(size_sufx), "-8x%d", _info.font_size);
5142089Ssos	}
515267540Sray	fd = openguess((vt4_mode == 0) ? a : vt4a, b, c, d, &name);
516146736Sdelphij
5172089Ssos	if (fd == NULL) {
518146736Sdelphij		revert();
519146736Sdelphij		errx(1, "%s: can't load font file", filename);
5202089Ssos	}
521146736Sdelphij
522267540Sray	if (vt4_mode) {
523313552Semaste		load_vt4font(fd);
524267540Sray		fclose(fd);
525267540Sray		return;
526267540Sray	}
527267540Sray
52875344Ssobomax	if (type != NULL) {
52975344Ssobomax		size = 0;
530146736Sdelphij		if (sscanf(type, "%dx%d", &w, &h) == 2) {
531146736Sdelphij			for (i = 0; sizes[i].w != 0; i++) {
53275344Ssobomax				if (sizes[i].w == w && sizes[i].h == h) {
53375344Ssobomax					size = DATASIZE(sizes[i]);
53475344Ssobomax					io = sizes[i].io;
535146736Sdelphij					font_height = sizes[i].h;
53675344Ssobomax				}
537146736Sdelphij			}
538146736Sdelphij		}
53975344Ssobomax		if (size == 0) {
54075344Ssobomax			fclose(fd);
541146736Sdelphij			revert();
542146736Sdelphij			errx(1, "%s: bad font size specification", type);
54375344Ssobomax		}
54475344Ssobomax	} else {
54575344Ssobomax		/* Apply heuristics */
546146736Sdelphij
54775344Ssobomax		int j;
54875344Ssobomax		int dsize[2];
54975344Ssobomax
55075344Ssobomax		size = DATASIZE(sizes[0]);
55175344Ssobomax		fontmap = (char*) malloc(size);
55275344Ssobomax		dsize[0] = decode(fd, fontmap, size);
55375344Ssobomax		dsize[1] = fsize(fd);
55475344Ssobomax		free(fontmap);
55575344Ssobomax
55675344Ssobomax		size = 0;
557146736Sdelphij		for (j = 0; j < 2; j++) {
558146736Sdelphij			for (i = 0; sizes[i].w != 0; i++) {
55975344Ssobomax				if (DATASIZE(sizes[i]) == dsize[j]) {
56075344Ssobomax					size = dsize[j];
56175344Ssobomax					io = sizes[i].io;
562146736Sdelphij					font_height = sizes[i].h;
56375344Ssobomax					j = 2;	/* XXX */
56475344Ssobomax					break;
56575344Ssobomax				}
566146736Sdelphij			}
567146736Sdelphij		}
56875344Ssobomax
56975344Ssobomax		if (size == 0) {
57075344Ssobomax			fclose(fd);
571146736Sdelphij			revert();
572146736Sdelphij			errx(1, "%s: can't guess font size", filename);
57375344Ssobomax		}
574146736Sdelphij
57575344Ssobomax		rewind(fd);
5762089Ssos	}
57775344Ssobomax
5782089Ssos	fontmap = (char*) malloc(size);
579146736Sdelphij
58075344Ssobomax	if (decode(fd, fontmap, size) != size) {
5812089Ssos		rewind(fd);
582146736Sdelphij		if (fsize(fd) != size ||
583146736Sdelphij		    fread(fontmap, 1, size, fd) != (size_t)size) {
58475344Ssobomax			warnx("%s: bad font file", filename);
58523457Sbrian			fclose(fd);
5862089Ssos			free(fontmap);
587146736Sdelphij			revert();
588146736Sdelphij			errx(1, "%s: bad font file", filename);
5892089Ssos		}
5902089Ssos	}
591146736Sdelphij
592146736Sdelphij	if (ioctl(0, io, fontmap) == -1) {
593146736Sdelphij		revert();
594146736Sdelphij		errc(1, errno, "loading font");
595146736Sdelphij	}
596146736Sdelphij
59723457Sbrian	fclose(fd);
5982089Ssos	free(fontmap);
5992089Ssos}
6002089Ssos
601146736Sdelphij
602146736Sdelphij/*
603146736Sdelphij * Set the timeout for the screensaver.
604146736Sdelphij */
605146736Sdelphij
606140159Sdelphijstatic void
6072089Ssosset_screensaver_timeout(char *arg)
6082089Ssos{
6092089Ssos	int nsec;
6102089Ssos
611146736Sdelphij	if (!strcmp(arg, "off")) {
6122089Ssos		nsec = 0;
613146736Sdelphij	} else {
6142089Ssos		nsec = atoi(arg);
615146736Sdelphij
6162089Ssos		if ((*arg == '\0') || (nsec < 1)) {
617146736Sdelphij			revert();
618146736Sdelphij			errx(1, "argument must be a positive number");
6192089Ssos		}
6202089Ssos	}
621146736Sdelphij
622146736Sdelphij	if (ioctl(0, CONS_BLANKTIME, &nsec) == -1) {
623146736Sdelphij		revert();
624146736Sdelphij		errc(1, errno, "setting screensaver period");
625146736Sdelphij	}
6262089Ssos}
6272089Ssos
628146736Sdelphij
629146736Sdelphij/*
630146736Sdelphij * Set the cursor's shape/type.
631146736Sdelphij */
632146736Sdelphij
633140159Sdelphijstatic void
634228990Suqsset_cursor_type(char *appearance)
6352089Ssos{
6365536Ssos	int type;
6372089Ssos
638228990Suqs	if (!strcmp(appearance, "normal"))
6396230Ssos		type = 0;
640228990Suqs	else if (!strcmp(appearance, "blink"))
6415536Ssos		type = 1;
642228990Suqs	else if (!strcmp(appearance, "destructive"))
6436230Ssos		type = 3;
6445536Ssos	else {
645146736Sdelphij		revert();
646146736Sdelphij		errx(1, "argument to -c must be normal, blink or destructive");
6472089Ssos	}
648146736Sdelphij
649146736Sdelphij	if (ioctl(0, CONS_CURSORTYPE, &type) == -1) {
650146736Sdelphij		revert();
651146736Sdelphij		errc(1, errno, "setting cursor type");
652146736Sdelphij	}
6532089Ssos}
6542089Ssos
655146736Sdelphij
656146736Sdelphij/*
657146736Sdelphij * Set the video mode.
658146736Sdelphij */
659146736Sdelphij
660140159Sdelphijstatic int
661146736Sdelphijvideo_mode(int argc, char **argv, int *mode_index)
6622089Ssos{
66339592Syokota	static struct {
664140159Sdelphij		const char *name;
66539592Syokota		unsigned long mode;
666146736Sdelphij		unsigned long mode_num;
66739592Syokota	} modes[] = {
668146736Sdelphij		{ "80x25",        SW_TEXT_80x25,   M_TEXT_80x25 },
669146736Sdelphij		{ "80x30",        SW_TEXT_80x30,   M_TEXT_80x30 },
670146736Sdelphij		{ "80x43",        SW_TEXT_80x43,   M_TEXT_80x43 },
671146736Sdelphij		{ "80x50",        SW_TEXT_80x50,   M_TEXT_80x50 },
672146736Sdelphij		{ "80x60",        SW_TEXT_80x60,   M_TEXT_80x60 },
673146736Sdelphij		{ "132x25",       SW_TEXT_132x25,  M_TEXT_132x25 },
674146736Sdelphij		{ "132x30",       SW_TEXT_132x30,  M_TEXT_132x30 },
675146736Sdelphij		{ "132x43",       SW_TEXT_132x43,  M_TEXT_132x43 },
676146736Sdelphij		{ "132x50",       SW_TEXT_132x50,  M_TEXT_132x50 },
677146736Sdelphij		{ "132x60",       SW_TEXT_132x60,  M_TEXT_132x60 },
678146736Sdelphij		{ "VGA_40x25",    SW_VGA_C40x25,   M_VGA_C40x25 },
679146736Sdelphij		{ "VGA_80x25",    SW_VGA_C80x25,   M_VGA_C80x25 },
680146736Sdelphij		{ "VGA_80x30",    SW_VGA_C80x30,   M_VGA_C80x30 },
681146736Sdelphij		{ "VGA_80x50",    SW_VGA_C80x50,   M_VGA_C80x50 },
682146736Sdelphij		{ "VGA_80x60",    SW_VGA_C80x60,   M_VGA_C80x60 },
68348105Syokota#ifdef SW_VGA_C90x25
684146736Sdelphij		{ "VGA_90x25",    SW_VGA_C90x25,   M_VGA_C90x25 },
685146736Sdelphij		{ "VGA_90x30",    SW_VGA_C90x30,   M_VGA_C90x30 },
686146736Sdelphij		{ "VGA_90x43",    SW_VGA_C90x43,   M_VGA_C90x43 },
687146736Sdelphij		{ "VGA_90x50",    SW_VGA_C90x50,   M_VGA_C90x50 },
688146736Sdelphij		{ "VGA_90x60",    SW_VGA_C90x60,   M_VGA_C90x60 },
68948105Syokota#endif
690146736Sdelphij		{ "VGA_320x200",	SW_VGA_CG320,	M_CG320 },
691146736Sdelphij		{ "EGA_80x25",		SW_ENH_C80x25,	M_ENH_C80x25 },
692146736Sdelphij		{ "EGA_80x43",		SW_ENH_C80x43,	M_ENH_C80x43 },
693146736Sdelphij		{ "VESA_132x25",	SW_VESA_C132x25,M_VESA_C132x25 },
694146736Sdelphij		{ "VESA_132x43",	SW_VESA_C132x43,M_VESA_C132x43 },
695146736Sdelphij		{ "VESA_132x50",	SW_VESA_C132x50,M_VESA_C132x50 },
696146736Sdelphij		{ "VESA_132x60",	SW_VESA_C132x60,M_VESA_C132x60 },
697146736Sdelphij		{ "VESA_800x600",	SW_VESA_800x600,M_VESA_800x600 },
698146736Sdelphij		{ NULL, 0, 0 },
69939592Syokota	};
700146736Sdelphij
701146736Sdelphij	int new_mode_num = 0;
70242605Smjacob	unsigned long mode = 0;
70348105Syokota	int cur_mode;
70448105Syokota	int ioerr;
70539287Ssos	int size[3];
70639592Syokota	int i;
7072089Ssos
70848105Syokota	if (ioctl(0, CONS_GET, &cur_mode) < 0)
70948105Syokota		err(1, "cannot get the current video mode");
710146736Sdelphij
711146736Sdelphij	/*
712146736Sdelphij	 * Parse the video mode argument...
713146736Sdelphij	 */
714146736Sdelphij
715146736Sdelphij	if (*mode_index < argc) {
716146736Sdelphij		if (!strncmp(argv[*mode_index], "MODE_", 5)) {
717146736Sdelphij			if (!isdigit(argv[*mode_index][5]))
718146736Sdelphij				errx(1, "invalid video mode number");
719146736Sdelphij
720146736Sdelphij			new_mode_num = atoi(&argv[*mode_index][5]);
721146736Sdelphij		} else {
722146736Sdelphij			for (i = 0; modes[i].name != NULL; ++i) {
723146736Sdelphij				if (!strcmp(argv[*mode_index], modes[i].name)) {
724146736Sdelphij					mode = modes[i].mode;
725146736Sdelphij					new_mode_num = modes[i].mode_num;
726146736Sdelphij					break;
727146736Sdelphij				}
72839592Syokota			}
729146736Sdelphij
730146736Sdelphij			if (modes[i].name == NULL)
731146736Sdelphij				return EXIT_FAILURE;
732146736Sdelphij			if (ioctl(0, mode, NULL) < 0) {
733146736Sdelphij				warn("cannot set videomode");
734146736Sdelphij				return EXIT_FAILURE;
735146736Sdelphij			}
73639592Syokota		}
737146736Sdelphij
738146736Sdelphij		/*
739146736Sdelphij		 * Collect enough information about the new video mode...
740146736Sdelphij		 */
741146736Sdelphij
742146736Sdelphij		new_mode_info.vi_mode = new_mode_num;
743146736Sdelphij
744146736Sdelphij		if (ioctl(0, CONS_MODEINFO, &new_mode_info) == -1) {
745146736Sdelphij			revert();
746146736Sdelphij			errc(1, errno, "obtaining new video mode parameters");
747120201Seivind		}
748146736Sdelphij
749146736Sdelphij		if (mode == 0) {
750146736Sdelphij			if (new_mode_num >= M_VESA_BASE)
751146736Sdelphij				mode = _IO('V', new_mode_num - M_VESA_BASE);
752146736Sdelphij			else
753146736Sdelphij				mode = _IO('S', new_mode_num);
754146736Sdelphij		}
755146736Sdelphij
756146736Sdelphij		/*
757146736Sdelphij		 * Try setting the new mode.
758146736Sdelphij		 */
759146736Sdelphij
760146736Sdelphij		if (ioctl(0, mode, NULL) == -1) {
761146736Sdelphij			revert();
762146736Sdelphij			errc(1, errno, "setting video mode");
763146736Sdelphij		}
764146736Sdelphij
765146736Sdelphij		/*
766146736Sdelphij		 * For raster modes it's not enough to just set the mode.
767146736Sdelphij		 * We also need to explicitly set the raster mode.
768146736Sdelphij		 */
769146736Sdelphij
770146736Sdelphij		if (new_mode_info.vi_flags & V_INFO_GRAPHICS) {
771146736Sdelphij			/* font size */
772146736Sdelphij
773146736Sdelphij			if (font_height == 0)
774146736Sdelphij				font_height = cur_info.console_info.font_size;
775146736Sdelphij
776146736Sdelphij			size[2] = font_height;
777146736Sdelphij
778146736Sdelphij			/* adjust columns */
779146736Sdelphij
780146736Sdelphij			if ((vesa_cols * 8 > new_mode_info.vi_width) ||
781146736Sdelphij			    (vesa_cols <= 0)) {
782146736Sdelphij				size[0] = new_mode_info.vi_width / 8;
78371642Ssobomax			} else {
78471642Ssobomax				size[0] = vesa_cols;
78571642Ssobomax			}
786146736Sdelphij
787146736Sdelphij			/* adjust rows */
788146736Sdelphij
789146736Sdelphij			if ((vesa_rows * font_height > new_mode_info.vi_height) ||
790146736Sdelphij			    (vesa_rows <= 0)) {
791146736Sdelphij				size[1] = new_mode_info.vi_height /
792146736Sdelphij					  font_height;
79371642Ssobomax			} else {
79471642Ssobomax				size[1] = vesa_rows;
79571642Ssobomax			}
796146736Sdelphij
797146736Sdelphij			/* set raster mode */
798146736Sdelphij
79948105Syokota			if (ioctl(0, KDRASTER, size)) {
80048105Syokota				ioerr = errno;
80148105Syokota				if (cur_mode >= M_VESA_BASE)
80280148Syokota					ioctl(0,
80380148Syokota					    _IO('V', cur_mode - M_VESA_BASE),
80480148Syokota					    NULL);
80548105Syokota				else
80648105Syokota					ioctl(0, _IO('S', cur_mode), NULL);
807146736Sdelphij				revert();
80848105Syokota				warnc(ioerr, "cannot activate raster display");
809120201Seivind				return EXIT_FAILURE;
81048105Syokota			}
81139287Ssos		}
812146736Sdelphij
813146736Sdelphij		video_mode_changed = 1;
814146736Sdelphij
815146736Sdelphij		(*mode_index)++;
8162089Ssos	}
817120201Seivind	return EXIT_SUCCESS;
8182089Ssos}
8198857Srgrimes
820146736Sdelphij
821146736Sdelphij/*
822146736Sdelphij * Return the number for a specified color name.
823146736Sdelphij */
824146736Sdelphij
825140159Sdelphijstatic int
8262089Ssosget_color_number(char *color)
8272089Ssos{
8282089Ssos	int i;
8292089Ssos
830146736Sdelphij	for (i=0; i<16; i++) {
8312089Ssos		if (!strcmp(color, legal_colors[i]))
8322089Ssos			return i;
833146736Sdelphij	}
8342089Ssos	return -1;
8352089Ssos}
8362089Ssos
837146736Sdelphij
838146736Sdelphij/*
839146736Sdelphij * Get normal text and background colors.
840146736Sdelphij */
841146736Sdelphij
842140159Sdelphijstatic void
843146736Sdelphijget_normal_colors(int argc, char **argv, int *_index)
8442089Ssos{
8452089Ssos	int color;
8462089Ssos
847140159Sdelphij	if (*_index < argc && (color = get_color_number(argv[*_index])) != -1) {
848140159Sdelphij		(*_index)++;
849146241Snyan		fprintf(stderr, "\033[=%dF", color);
850150246Srodrigc		normal_fore_color=color;
851150246Srodrigc		colors_changed = 1;
852140159Sdelphij		if (*_index < argc
853140159Sdelphij		    && (color = get_color_number(argv[*_index])) != -1
8542089Ssos		    && color < 8) {
855140159Sdelphij			(*_index)++;
856146241Snyan			fprintf(stderr, "\033[=%dG", color);
857150246Srodrigc			normal_back_color=color;
8582089Ssos		}
8592089Ssos	}
8602089Ssos}
8612089Ssos
862146736Sdelphij
863146736Sdelphij/*
864146736Sdelphij * Get reverse text and background colors.
865146736Sdelphij */
866146736Sdelphij
867140159Sdelphijstatic void
868146736Sdelphijget_reverse_colors(int argc, char **argv, int *_index)
8692089Ssos{
8702089Ssos	int color;
8712089Ssos
872140159Sdelphij	if ((color = get_color_number(argv[*(_index)-1])) != -1) {
873146241Snyan		fprintf(stderr, "\033[=%dH", color);
874150246Srodrigc		revers_fore_color=color;
875150246Srodrigc		colors_changed = 1;
876140159Sdelphij		if (*_index < argc
877140159Sdelphij		    && (color = get_color_number(argv[*_index])) != -1
8782089Ssos		    && color < 8) {
879140159Sdelphij			(*_index)++;
880146241Snyan			fprintf(stderr, "\033[=%dI", color);
881150246Srodrigc			revers_back_color=color;
8822089Ssos		}
8832089Ssos	}
8842089Ssos}
8852089Ssos
886146736Sdelphij
887146736Sdelphij/*
888146736Sdelphij * Set normal and reverse foreground and background colors.
889146736Sdelphij */
890146736Sdelphij
891140159Sdelphijstatic void
892146736Sdelphijset_colors(void)
893146736Sdelphij{
894146736Sdelphij	fprintf(stderr, "\033[=%dF", normal_fore_color);
895146736Sdelphij	fprintf(stderr, "\033[=%dG", normal_back_color);
896146736Sdelphij	fprintf(stderr, "\033[=%dH", revers_fore_color);
897146736Sdelphij	fprintf(stderr, "\033[=%dI", revers_back_color);
898146736Sdelphij}
899146736Sdelphij
900146736Sdelphij
901146736Sdelphij/*
902146736Sdelphij * Switch to virtual terminal #arg.
903146736Sdelphij */
904146736Sdelphij
905146736Sdelphijstatic void
90623457Sbrianset_console(char *arg)
90723457Sbrian{
90823457Sbrian	int n;
90923457Sbrian
910146736Sdelphij	if(!arg || strspn(arg,"0123456789") != strlen(arg)) {
911146736Sdelphij		revert();
912146736Sdelphij		errx(1, "bad console number");
91323457Sbrian	}
91423457Sbrian
91523457Sbrian	n = atoi(arg);
916146736Sdelphij
91751393Syokota	if (n < 1 || n > 16) {
918146736Sdelphij		revert();
919146736Sdelphij		errx(1, "console number out of range");
920162671Sru	} else if (ioctl(0, VT_ACTIVATE, n) == -1) {
921146736Sdelphij		revert();
922146736Sdelphij		errc(1, errno, "switching vty");
923146736Sdelphij	}
92423457Sbrian}
92523457Sbrian
926146736Sdelphij
927146736Sdelphij/*
928146736Sdelphij * Sets the border color.
929146736Sdelphij */
930146736Sdelphij
931140159Sdelphijstatic void
9322089Ssosset_border_color(char *arg)
9332089Ssos{
9342089Ssos	int color;
9352089Ssos
9362089Ssos	if ((color = get_color_number(arg)) != -1) {
937146241Snyan		fprintf(stderr, "\033[=%dA", color);
9382089Ssos	}
9392089Ssos	else
9408857Srgrimes		usage();
9412089Ssos}
9422089Ssos
943140159Sdelphijstatic void
94455849Syokotaset_mouse_char(char *arg)
94555849Syokota{
94655849Syokota	struct mouse_info mouse;
94755849Syokota	long l;
94855849Syokota
94955849Syokota	l = strtol(arg, NULL, 0);
950146736Sdelphij
95175788Sache	if ((l < 0) || (l > UCHAR_MAX - 3)) {
952146736Sdelphij		revert();
95375788Sache		warnx("argument to -M must be 0 through %d", UCHAR_MAX - 3);
95455849Syokota		return;
95555849Syokota	}
956146736Sdelphij
95755849Syokota	mouse.operation = MOUSE_MOUSECHAR;
95855849Syokota	mouse.u.mouse_char = (int)l;
959146736Sdelphij
960146736Sdelphij	if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) {
961146736Sdelphij		revert();
962146736Sdelphij		errc(1, errno, "setting mouse character");
963146736Sdelphij	}
96455849Syokota}
96555849Syokota
966146736Sdelphij
967146736Sdelphij/*
968146736Sdelphij * Show/hide the mouse.
969146736Sdelphij */
970146736Sdelphij
971140159Sdelphijstatic void
97216565Ssosset_mouse(char *arg)
97316565Ssos{
97416565Ssos	struct mouse_info mouse;
97516565Ssos
976146736Sdelphij	if (!strcmp(arg, "on")) {
97716565Ssos		mouse.operation = MOUSE_SHOW;
978146736Sdelphij	} else if (!strcmp(arg, "off")) {
97916565Ssos		mouse.operation = MOUSE_HIDE;
980146736Sdelphij	} else {
981146736Sdelphij		revert();
982146736Sdelphij		errx(1, "argument to -m must be either on or off");
98316565Ssos	}
984146736Sdelphij
985146736Sdelphij	if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) {
986146736Sdelphij		revert();
987146736Sdelphij		errc(1, errno, "%sing the mouse",
988146736Sdelphij		     mouse.operation == MOUSE_SHOW ? "show" : "hid");
989146736Sdelphij	}
99016565Ssos}
99116565Ssos
992146736Sdelphij
993140159Sdelphijstatic void
99499705Sddset_lockswitch(char *arg)
99599705Sdd{
99699705Sdd	int data;
99799705Sdd
998146736Sdelphij	if (!strcmp(arg, "off")) {
99999705Sdd		data = 0x01;
1000146736Sdelphij	} else if (!strcmp(arg, "on")) {
100199705Sdd		data = 0x02;
1002146736Sdelphij	} else {
1003146736Sdelphij		revert();
1004146736Sdelphij		errx(1, "argument to -S must be either on or off");
100599705Sdd	}
1006146736Sdelphij
1007146736Sdelphij	if (ioctl(0, VT_LOCKSWITCH, &data) == -1) {
1008146736Sdelphij		revert();
1009146736Sdelphij		errc(1, errno, "turning %s vty switching",
1010146736Sdelphij		     data == 0x01 ? "off" : "on");
1011146736Sdelphij	}
101299705Sdd}
101399705Sdd
1014146736Sdelphij
1015146736Sdelphij/*
1016146736Sdelphij * Return the adapter name for a specified type.
1017146736Sdelphij */
1018146736Sdelphij
1019140159Sdelphijstatic const char
102039287Ssos*adapter_name(int type)
102139287Ssos{
102239287Ssos    static struct {
102339287Ssos	int type;
1024140159Sdelphij	const char *name;
102539287Ssos    } names[] = {
102639287Ssos	{ KD_MONO,	"MDA" },
102739287Ssos	{ KD_HERCULES,	"Hercules" },
102839287Ssos	{ KD_CGA,	"CGA" },
102939287Ssos	{ KD_EGA,	"EGA" },
103039287Ssos	{ KD_VGA,	"VGA" },
103139287Ssos	{ KD_PC98,	"PC-98xx" },
103248105Syokota	{ KD_TGA,	"TGA" },
103339287Ssos	{ -1,		"Unknown" },
103439287Ssos    };
1035146736Sdelphij
103639287Ssos    int i;
103739287Ssos
103839287Ssos    for (i = 0; names[i].type != -1; ++i)
103939287Ssos	if (names[i].type == type)
104039287Ssos	    break;
104139287Ssos    return names[i].name;
104239287Ssos}
104339287Ssos
1044146736Sdelphij
1045146736Sdelphij/*
1046146736Sdelphij * Show graphics adapter information.
1047146736Sdelphij */
1048146736Sdelphij
1049140159Sdelphijstatic void
105039287Ssosshow_adapter_info(void)
105139287Ssos{
105242505Syokota	struct video_adapter_info ad;
105339287Ssos
105439287Ssos	ad.va_index = 0;
1055146736Sdelphij
1056146736Sdelphij	if (ioctl(0, CONS_ADPINFO, &ad) == -1) {
1057146736Sdelphij		revert();
1058146736Sdelphij		errc(1, errno, "obtaining adapter information");
105939287Ssos	}
106039287Ssos
106142505Syokota	printf("fb%d:\n", ad.va_index);
106242505Syokota	printf("    %.*s%d, type:%s%s (%d), flags:0x%x\n",
106342505Syokota	       (int)sizeof(ad.va_name), ad.va_name, ad.va_unit,
106439287Ssos	       (ad.va_flags & V_ADP_VESA) ? "VESA " : "",
106542505Syokota	       adapter_name(ad.va_type), ad.va_type, ad.va_flags);
106639287Ssos	printf("    initial mode:%d, current mode:%d, BIOS mode:%d\n",
106739287Ssos	       ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode);
1068140159Sdelphij	printf("    frame buffer window:0x%zx, buffer size:0x%zx\n",
106948105Syokota	       ad.va_window, ad.va_buffer_size);
1070140159Sdelphij	printf("    window size:0x%zx, origin:0x%x\n",
107148105Syokota	       ad.va_window_size, ad.va_window_orig);
107248105Syokota	printf("    display start address (%d, %d), scan line width:%d\n",
107348105Syokota	       ad.va_disp_start.x, ad.va_disp_start.y, ad.va_line_width);
1074140159Sdelphij	printf("    reserved:0x%zx\n", ad.va_unused0);
107539287Ssos}
107639287Ssos
1077146736Sdelphij
1078146736Sdelphij/*
1079146736Sdelphij * Show video mode information.
1080146736Sdelphij */
1081146736Sdelphij
1082140159Sdelphijstatic void
108339287Ssosshow_mode_info(void)
108439287Ssos{
1085205855Sjkim	char buf[80];
1086140159Sdelphij	struct video_info _info;
1087205855Sjkim	int c;
1088205855Sjkim	int mm;
108939287Ssos	int mode;
109039287Ssos
109139287Ssos	printf("    mode#     flags   type    size       "
109239287Ssos	       "font      window      linear buffer\n");
109339287Ssos	printf("---------------------------------------"
109439287Ssos	       "---------------------------------------\n");
1095146736Sdelphij
1096250509Seadler	for (mode = 0; mode <= M_VESA_MODE_MAX; ++mode) {
1097140159Sdelphij		_info.vi_mode = mode;
1098140159Sdelphij		if (ioctl(0, CONS_MODEINFO, &_info))
109939287Ssos			continue;
1100140159Sdelphij		if (_info.vi_mode != mode)
110148105Syokota			continue;
110239287Ssos
110339287Ssos		printf("%3d (0x%03x)", mode, mode);
1104140159Sdelphij    		printf(" 0x%08x", _info.vi_flags);
1105140159Sdelphij		if (_info.vi_flags & V_INFO_GRAPHICS) {
110639287Ssos			c = 'G';
1107146736Sdelphij
1108205855Sjkim			if (_info.vi_mem_model == V_INFO_MM_PLANAR)
1109205855Sjkim				snprintf(buf, sizeof(buf), "%dx%dx%d %d",
1110205855Sjkim				    _info.vi_width, _info.vi_height,
1111205855Sjkim				    _info.vi_depth, _info.vi_planes);
1112205855Sjkim			else {
1113205855Sjkim				switch (_info.vi_mem_model) {
1114205855Sjkim				case V_INFO_MM_PACKED:
1115205855Sjkim					mm = 'P';
1116205855Sjkim					break;
1117205855Sjkim				case V_INFO_MM_DIRECT:
1118205855Sjkim					mm = 'D';
1119205855Sjkim					break;
1120205855Sjkim				case V_INFO_MM_CGA:
1121205855Sjkim					mm = 'C';
1122205855Sjkim					break;
1123205855Sjkim				case V_INFO_MM_HGC:
1124205855Sjkim					mm = 'H';
1125205855Sjkim					break;
1126205855Sjkim				case V_INFO_MM_VGAX:
1127205855Sjkim					mm = 'V';
1128205855Sjkim					break;
1129205855Sjkim				default:
1130205855Sjkim					mm = ' ';
1131205855Sjkim					break;
1132205855Sjkim				}
1133205855Sjkim				snprintf(buf, sizeof(buf), "%dx%dx%d %c",
1134205855Sjkim				    _info.vi_width, _info.vi_height,
1135205855Sjkim				    _info.vi_depth, mm);
1136205855Sjkim			}
113739287Ssos		} else {
113839287Ssos			c = 'T';
1139146736Sdelphij
114039287Ssos			snprintf(buf, sizeof(buf), "%dx%d",
1141140159Sdelphij				 _info.vi_width, _info.vi_height);
114239287Ssos		}
1143146736Sdelphij
114439287Ssos		printf(" %c %-15s", c, buf);
114539287Ssos		snprintf(buf, sizeof(buf), "%dx%d",
1146140159Sdelphij			 _info.vi_cwidth, _info.vi_cheight);
114739287Ssos		printf(" %-5s", buf);
1148140159Sdelphij    		printf(" 0x%05zx %2dk %2dk",
1149140159Sdelphij		       _info.vi_window, (int)_info.vi_window_size/1024,
1150140159Sdelphij		       (int)_info.vi_window_gran/1024);
1151140159Sdelphij    		printf(" 0x%08zx %dk\n",
1152140159Sdelphij		       _info.vi_buffer, (int)_info.vi_buffer_size/1024);
115339287Ssos	}
115439287Ssos}
115539287Ssos
1156146736Sdelphij
1157140159Sdelphijstatic void
115839287Ssosshow_info(char *arg)
115939287Ssos{
1160146736Sdelphij	if (!strcmp(arg, "adapter")) {
116139287Ssos		show_adapter_info();
1162146736Sdelphij	} else if (!strcmp(arg, "mode")) {
116339287Ssos		show_mode_info();
1164146736Sdelphij	} else {
1165146736Sdelphij		revert();
1166146736Sdelphij		errx(1, "argument to -i must be either adapter or mode");
116739287Ssos	}
116839287Ssos}
116939287Ssos
1170146736Sdelphij
1171140159Sdelphijstatic void
1172140159Sdelphijtest_frame(void)
11732089Ssos{
1174146237Snyan	int i, cur_mode, fore;
11752089Ssos
1176146237Snyan	fore = 15;
1177146237Snyan
1178146237Snyan	if (ioctl(0, CONS_GET, &cur_mode) < 0)
1179146237Snyan		err(1, "must be on a virtual console");
1180146237Snyan	switch (cur_mode) {
1181146237Snyan	case M_PC98_80x25:
1182146237Snyan	case M_PC98_80x30:
1183146237Snyan		fore = 7;
1184146237Snyan		break;
1185146237Snyan	}
1186146237Snyan
1187146241Snyan	fprintf(stdout, "\033[=0G\n\n");
11882089Ssos	for (i=0; i<8; i++) {
1189146241Snyan		fprintf(stdout, "\033[=%dF\033[=0G        %2d \033[=%dF%-16s"
1190146241Snyan				"\033[=%dF\033[=0G        %2d \033[=%dF%-16s        "
1191146241Snyan				"\033[=%dF %2d \033[=%dGBACKGROUND\033[=0G\n",
1192146237Snyan			fore, i, i, legal_colors[i],
1193146237Snyan			fore, i+8, i+8, legal_colors[i+8],
1194146237Snyan			fore, i, i);
11952089Ssos	}
1196146241Snyan	fprintf(stdout, "\033[=%dF\033[=%dG\033[=%dH\033[=%dI\n",
11978857Srgrimes		info.mv_norm.fore, info.mv_norm.back,
11982089Ssos		info.mv_rev.fore, info.mv_rev.back);
11992089Ssos}
12002089Ssos
1201146736Sdelphij
120276845Ssobomax/*
120376845Ssobomax * Snapshot the video memory of that terminal, using the CONS_SCRSHOT
120476845Ssobomax * ioctl, and writes the results to stdout either in the special
120576845Ssobomax * binary format (see manual page for details), or in the plain
120676845Ssobomax * text format.
120776845Ssobomax */
1208146736Sdelphij
1209140159Sdelphijstatic void
1210102111Ssobomaxdump_screen(int mode, int opt)
121176845Ssobomax{
121276845Ssobomax	scrshot_t shot;
1213140159Sdelphij	vid_info_t _info;
121476845Ssobomax
1215140159Sdelphij	_info.size = sizeof(_info);
1216146736Sdelphij
1217140159Sdelphij	if (ioctl(0, CONS_GETINFO, &_info) == -1) {
1218146736Sdelphij		revert();
1219146736Sdelphij		errc(1, errno, "obtaining current video mode parameters");
122076845Ssobomax		return;
122176845Ssobomax	}
122276845Ssobomax
1223102111Ssobomax	shot.x = shot.y = 0;
1224140159Sdelphij	shot.xsize = _info.mv_csz;
1225140159Sdelphij	shot.ysize = _info.mv_rsz;
1226102111Ssobomax	if (opt == DUMP_ALL)
1227140159Sdelphij		shot.ysize += _info.mv_hsz;
1228102111Ssobomax
1229102111Ssobomax	shot.buf = alloca(shot.xsize * shot.ysize * sizeof(u_int16_t));
123076845Ssobomax	if (shot.buf == NULL) {
1231146736Sdelphij		revert();
1232146736Sdelphij		errx(1, "failed to allocate memory for dump");
123376845Ssobomax	}
123476845Ssobomax
123576845Ssobomax	if (ioctl(0, CONS_SCRSHOT, &shot) == -1) {
1236146736Sdelphij		revert();
1237146736Sdelphij		errc(1, errno, "dumping screen");
123876845Ssobomax	}
123976845Ssobomax
1240102111Ssobomax	if (mode == DUMP_FMT_RAW) {
124176845Ssobomax		printf("SCRSHOT_%c%c%c%c", DUMP_FMT_REV, 2,
124276845Ssobomax		       shot.xsize, shot.ysize);
1243146736Sdelphij
124476845Ssobomax		fflush(stdout);
124576845Ssobomax
1246146736Sdelphij		write(STDOUT_FILENO, shot.buf,
1247146736Sdelphij		      shot.xsize * shot.ysize * sizeof(u_int16_t));
124876845Ssobomax	} else {
124976845Ssobomax		char *line;
125076845Ssobomax		int x, y;
125176845Ssobomax		u_int16_t ch;
125276845Ssobomax
125376845Ssobomax		line = alloca(shot.xsize + 1);
1254146736Sdelphij
125576845Ssobomax		if (line == NULL) {
1256146736Sdelphij			revert();
1257146736Sdelphij			errx(1, "failed to allocate memory for line buffer");
125876845Ssobomax		}
125976845Ssobomax
126076845Ssobomax		for (y = 0; y < shot.ysize; y++) {
126176845Ssobomax			for (x = 0; x < shot.xsize; x++) {
126276845Ssobomax				ch = shot.buf[x + (y * shot.xsize)];
126376845Ssobomax				ch &= 0xff;
1264146736Sdelphij
126576845Ssobomax				if (isprint(ch) == 0)
126676845Ssobomax					ch = ' ';
1267146736Sdelphij
126876845Ssobomax				line[x] = (char)ch;
126976845Ssobomax			}
127076845Ssobomax
127176845Ssobomax			/* Trim trailing spaces */
1272146736Sdelphij
127376845Ssobomax			do {
127476845Ssobomax				line[x--] = '\0';
127576845Ssobomax			} while (line[x] == ' ' && x != 0);
127676845Ssobomax
127776845Ssobomax			puts(line);
127876845Ssobomax		}
1279146736Sdelphij
128076845Ssobomax		fflush(stdout);
128176845Ssobomax	}
128276845Ssobomax}
128376845Ssobomax
1284146736Sdelphij
1285146736Sdelphij/*
1286146736Sdelphij * Set the console history buffer size.
1287146736Sdelphij */
1288146736Sdelphij
1289140159Sdelphijstatic void
129077329Sdesset_history(char *opt)
129177329Sdes{
129277329Sdes	int size;
129377329Sdes
129477329Sdes	size = atoi(opt);
1295146736Sdelphij
129677329Sdes	if ((*opt == '\0') || size < 0) {
1297146736Sdelphij		revert();
1298146736Sdelphij		errx(1, "argument must be a positive number");
129977329Sdes	}
1300146736Sdelphij
1301146736Sdelphij	if (ioctl(0, CONS_HISTORY, &size) == -1) {
1302146736Sdelphij		revert();
1303146736Sdelphij		errc(1, errno, "setting history buffer size");
1304146736Sdelphij	}
130577329Sdes}
130677329Sdes
1307146736Sdelphij
1308146736Sdelphij/*
1309146736Sdelphij * Clear the console history buffer.
1310146736Sdelphij */
1311146736Sdelphij
1312140159Sdelphijstatic void
1313140159Sdelphijclear_history(void)
131477329Sdes{
1315146736Sdelphij	if (ioctl(0, CONS_CLRHIST) == -1) {
1316146736Sdelphij		revert();
1317146736Sdelphij		errc(1, errno, "clearing history buffer");
1318146736Sdelphij	}
131977329Sdes}
132077329Sdes
1321199174Sedstatic void
1322199174Sedset_terminal_mode(char *arg)
1323199174Sed{
1324146736Sdelphij
1325199174Sed	if (strcmp(arg, "xterm") == 0)
1326199174Sed		fprintf(stderr, "\033[=T");
1327199174Sed	else if (strcmp(arg, "cons25") == 0)
1328199174Sed		fprintf(stderr, "\033[=1T");
1329199174Sed}
1330199174Sed
1331199174Sed
133223457Sbrianint
13332089Ssosmain(int argc, char **argv)
13342089Ssos{
1335237777Sache	char    *font, *type, *termmode;
1336267540Sray	const char *opts;
1337102111Ssobomax	int	dumpmod, dumpopt, opt;
1338120201Seivind	int	reterr;
13392089Ssos
1340267540Sray	vt4_mode = is_vt4();
1341267540Sray
1342146736Sdelphij	init();
1343146736Sdelphij
13442089Ssos	info.size = sizeof(info);
1345146736Sdelphij
1346146736Sdelphij	if (ioctl(0, CONS_GETINFO, &info) == -1)
134730764Scharnier		err(1, "must be on a virtual console");
1348102111Ssobomax	dumpmod = 0;
1349102111Ssobomax	dumpopt = DUMP_FBF;
1350237777Sache	termmode = NULL;
1351267540Sray	if (vt4_mode)
1352273921Sdumbbell		opts = "b:Cc:fg:h:Hi:M:m:pPr:S:s:T:t:x";
1353267540Sray	else
1354286291Semaste		opts = "b:Cc:dfg:h:Hi:l:LM:m:pPr:S:s:T:t:x";
1355267540Sray
1356267540Sray	while ((opt = getopt(argc, argv, opts)) != -1)
13572089Ssos		switch(opt) {
135877329Sdes		case 'b':
135977329Sdes			set_border_color(optarg);
136077329Sdes			break;
136177329Sdes		case 'C':
136277329Sdes			clear_history();
136377329Sdes			break;
136477329Sdes		case 'c':
136577329Sdes			set_cursor_type(optarg);
136677329Sdes			break;
136777329Sdes		case 'd':
1368267540Sray			if (vt4_mode)
1369267540Sray				break;
137077329Sdes			print_scrnmap();
137177329Sdes			break;
137277329Sdes		case 'f':
1373273921Sdumbbell			optarg = nextarg(argc, argv, &optind, 'f', 0);
1374273921Sdumbbell			if (optarg != NULL) {
1375273921Sdumbbell				font = nextarg(argc, argv, &optind, 'f', 0);
1376146736Sdelphij
1377273921Sdumbbell				if (font == NULL) {
1378273921Sdumbbell					type = NULL;
1379273921Sdumbbell					font = optarg;
1380273921Sdumbbell				} else
1381273921Sdumbbell					type = optarg;
1382273921Sdumbbell
1383273921Sdumbbell				load_font(type, font);
1384273921Sdumbbell			} else {
1385273921Sdumbbell				if (!vt4_mode)
1386273921Sdumbbell					usage(); /* Switch syscons to ROM? */
1387273921Sdumbbell
1388273921Sdumbbell				load_default_vt4font();
138977329Sdes			}
139077329Sdes			break;
139177329Sdes		case 'g':
1392146736Sdelphij			if (sscanf(optarg, "%dx%d",
1393146736Sdelphij			    &vesa_cols, &vesa_rows) != 2) {
1394146736Sdelphij				revert();
139577329Sdes				warnx("incorrect geometry: %s", optarg);
13962089Ssos				usage();
139777329Sdes			}
1398146736Sdelphij                	break;
139977329Sdes		case 'h':
140077329Sdes			set_history(optarg);
140177329Sdes			break;
1402102111Ssobomax		case 'H':
1403102111Ssobomax			dumpopt = DUMP_ALL;
1404102111Ssobomax			break;
140577329Sdes		case 'i':
140677329Sdes			show_info(optarg);
140777329Sdes			break;
140877329Sdes		case 'l':
1409267540Sray			if (vt4_mode)
1410267540Sray				break;
141177329Sdes			load_scrnmap(optarg);
141277329Sdes			break;
141377329Sdes		case 'L':
1414267540Sray			if (vt4_mode)
1415267540Sray				break;
141677329Sdes			load_default_scrnmap();
141777329Sdes			break;
141877329Sdes		case 'M':
141977329Sdes			set_mouse_char(optarg);
142077329Sdes			break;
142177329Sdes		case 'm':
142277329Sdes			set_mouse(optarg);
142377329Sdes			break;
142477329Sdes		case 'p':
1425102111Ssobomax			dumpmod = DUMP_FMT_RAW;
142677329Sdes			break;
142777329Sdes		case 'P':
1428102111Ssobomax			dumpmod = DUMP_FMT_TXT;
142977329Sdes			break;
143077329Sdes		case 'r':
1431146736Sdelphij			get_reverse_colors(argc, argv, &optind);
143277329Sdes			break;
143399705Sdd		case 'S':
143499705Sdd			set_lockswitch(optarg);
143599705Sdd			break;
143677329Sdes		case 's':
143777329Sdes			set_console(optarg);
143877329Sdes			break;
1439199174Sed		case 'T':
1440237777Sache			if (strcmp(optarg, "xterm") != 0 &&
1441237777Sache			    strcmp(optarg, "cons25") != 0)
1442237777Sache				usage();
1443237777Sache			termmode = optarg;
1444199174Sed			break;
144577329Sdes		case 't':
144677329Sdes			set_screensaver_timeout(optarg);
144777329Sdes			break;
144877329Sdes		case 'x':
144977329Sdes			hex = 1;
145077329Sdes			break;
145177329Sdes		default:
145277329Sdes			usage();
14532089Ssos		}
1454146736Sdelphij
1455102111Ssobomax	if (dumpmod != 0)
1456102111Ssobomax		dump_screen(dumpmod, dumpopt);
1457120201Seivind	reterr = video_mode(argc, argv, &optind);
1458146736Sdelphij	get_normal_colors(argc, argv, &optind);
1459146736Sdelphij
14602089Ssos	if (optind < argc && !strcmp(argv[optind], "show")) {
14612089Ssos		test_frame();
14622089Ssos		optind++;
14632089Ssos	}
1464146736Sdelphij
1465146736Sdelphij	video_mode(argc, argv, &optind);
1466237777Sache	if (termmode != NULL)
1467237777Sache		set_terminal_mode(termmode);
1468146736Sdelphij
1469146736Sdelphij	get_normal_colors(argc, argv, &optind);
1470146736Sdelphij
1471146736Sdelphij	if (colors_changed || video_mode_changed) {
1472146736Sdelphij		if (!(new_mode_info.vi_flags & V_INFO_GRAPHICS)) {
1473146736Sdelphij			if ((normal_back_color < 8) && (revers_back_color < 8)) {
1474146736Sdelphij				set_colors();
1475146736Sdelphij			} else {
1476146736Sdelphij				revert();
1477146736Sdelphij				errx(1, "bg color for text modes must be < 8");
1478146736Sdelphij			}
1479146736Sdelphij		} else {
1480146736Sdelphij			set_colors();
1481146736Sdelphij		}
1482146736Sdelphij	}
1483146736Sdelphij
148430764Scharnier	if ((optind != argc) || (argc == 1))
14852089Ssos		usage();
1486120201Seivind	return reterr;
14872089Ssos}
14882089Ssos
1489