daemon_saver.c revision 331722
1/*-
2 * Copyright (c) 1997 Sandro Sigala, Brescia, Italy.
3 * Copyright (c) 1997 Chris Shenton
4 * Copyright (c) 1995 S��ren Schmidt
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer
12 *    in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: stable/11/sys/dev/syscons/daemon/daemon_saver.c 331722 2018-03-29 02:50:57Z eadler $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/module.h>
34#include <sys/malloc.h>
35#include <sys/jail.h>
36#include <sys/kernel.h>
37#include <sys/sysctl.h>
38#include <sys/consio.h>
39#include <sys/fbio.h>
40
41#include <machine/pc/display.h>
42
43#include <dev/fb/fbreg.h>
44#include <dev/fb/splashreg.h>
45#include <dev/syscons/syscons.h>
46
47#define DAEMON_MAX_WIDTH	32
48#define DAEMON_MAX_HEIGHT	19
49
50static u_char *message;
51static int messagelen;
52static int blanked;
53static int attr_mask;
54
55#define	ATTR(attr)	(((attr) & attr_mask) << 8)
56
57/* Who is the author of this ASCII pic? */
58
59static u_char *daemon_pic[] = {
60        "             ,        ,",
61	"            /(        )`",
62	"            \\ \\___   / |",
63	"            /- _  `-/  '",
64	"           (/\\/ \\ \\   /\\",
65	"           / /   | `    \\",
66	"           O O   ) /    |",
67	"           `-^--'`<     '",
68	"          (_.)  _  )   /",
69	"           `.___/`    /",
70	"             `-----' /",
71	"<----.     __ / __   \\",
72	"<----|====O)))==) \\) /====",
73	"<----'    `--' `.__,' \\",
74	"             |        |",
75	"              \\       /       /\\",
76	"         ______( (_  / \\______/",
77	"       ,'  ,-----'   |",
78	"       `--{__________)",
79	NULL
80};
81
82static u_char *daemon_attr[] = {
83        "             R        R",
84	"            RR        RR",
85	"            R RRRR   R R",
86	"            RR W  RRR  R",
87	"           RWWW W R   RR",
88	"           W W   W R    R",
89	"           B B   W R    R",
90	"           WWWWWWRR     R",
91	"          RRRR  R  R   R",
92	"           RRRRRRR    R",
93	"             RRRRRRR R",
94	"YYYYYY     RR R RR   R",
95	"YYYYYYYYYYRRRRYYR RR RYYYY",
96	"YYYYYY    RRRR RRRRRR R",
97	"             R        R",
98	"              R       R       RR",
99	"         CCCCCCR RR  R RRRRRRRR",
100	"       CC  CCCCCCC   C",
101	"       CCCCCCCCCCCCCCC",
102	NULL
103};
104
105/*
106 * Reverse a graphics character, or return unaltered if no mirror;
107 * should do alphanumerics too, but I'm too lazy. <cshenton@it.hq.nasa.gov>
108 */
109
110static u_char
111xflip_symbol(u_char symbol)
112{
113	static const u_char lchars[] = "`'(){}[]\\/<>";
114	static const u_char rchars[] = "'`)(}{][/\\><";
115	int pos;
116
117	for (pos = 0; lchars[pos] != '\0'; pos++)
118		if (lchars[pos] == symbol)
119			return rchars[pos];
120
121	return symbol;
122}
123
124static void
125clear_daemon(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff,
126	    int xlen, int ylen)
127{
128	int y;
129
130	if (xlen <= 0)
131		return;
132	for (y = yoff; y < ylen; y++) {
133		sc_vtb_erase(&sc->cur_scp->scr,
134			     (ypos + y)*sc->cur_scp->xsize + xpos + xoff,
135			     xlen - xoff,
136			     sc->scr_map[0x20], ATTR(FG_LIGHTGREY | BG_BLACK));
137	}
138}
139
140static void
141draw_daemon(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff,
142	    int xlen, int ylen)
143{
144	int x, y;
145	int px;
146	int attr;
147
148	for (y = yoff; y < ylen; y++) {
149		if (dxdir < 0)
150			px = xoff;
151		else
152			px = DAEMON_MAX_WIDTH - xlen;
153		if (px >= strlen(daemon_pic[y]))
154			continue;
155		for (x = xoff; (x < xlen) && (daemon_pic[y][px] != '\0'); x++, px++) {
156			switch (daemon_attr[y][px]) {
157			case 'R': attr = FG_LIGHTRED | BG_BLACK; break;
158			case 'Y': attr = FG_YELLOW | BG_BLACK; break;
159			case 'B': attr = FG_LIGHTBLUE | BG_BLACK; break;
160			case 'W': attr = FG_LIGHTGREY | BG_BLACK; break;
161			case 'C': attr = FG_CYAN | BG_BLACK; break;
162			default: attr = FG_WHITE | BG_BLACK; break;
163			}
164			if (dxdir < 0) {	/* Moving left */
165				sc_vtb_putc(&sc->cur_scp->scr,
166					    (ypos + y)*sc->cur_scp->xsize
167						 + xpos + x,
168					    sc->scr_map[daemon_pic[y][px]],
169					    ATTR(attr));
170			} else {		/* Moving right */
171				sc_vtb_putc(&sc->cur_scp->scr,
172					    (ypos + y)*sc->cur_scp->xsize
173						+ xpos + DAEMON_MAX_WIDTH
174						- px - 1,
175					    sc->scr_map[xflip_symbol(daemon_pic[y][px])],
176					    ATTR(attr));
177			}
178		}
179	}
180}
181
182static void
183clear_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len)
184{
185	if (len <= 0)
186		return;
187	sc_vtb_erase(&sc->cur_scp->scr,
188		     ypos*sc->cur_scp->xsize + xpos + xoff, len - xoff,
189		     sc->scr_map[0x20], ATTR(FG_LIGHTGREY | BG_BLACK));
190}
191
192static void
193draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, u_char *s, int len)
194{
195	int x;
196
197	for (x = xoff; x < len; x++)
198		sc_vtb_putc(&sc->cur_scp->scr,
199			    ypos*sc->cur_scp->xsize + xpos + x,
200			    sc->scr_map[s[x]], ATTR(FG_LIGHTGREEN | BG_BLACK));
201}
202
203static int
204daemon_saver(video_adapter_t *adp, int blank)
205{
206	static int txpos = 10, typos = 10;
207	static int txdir = -1, tydir = -1;
208	static int dxpos = 0, dypos = 0;
209	static int dxdir = 1, dydir = 1;
210	static int moved_daemon = 0;
211	static int xoff, yoff, toff;
212	static int xlen, ylen, tlen;
213	sc_softc_t *sc;
214	scr_stat *scp;
215	int min, max;
216
217	sc = sc_find_softc(adp, NULL);
218	if (sc == NULL)
219		return EAGAIN;
220	scp = sc->cur_scp;
221
222	if (blank) {
223		if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
224			return EAGAIN;
225		if (blanked == 0) {
226			/* clear the screen and set the border color */
227			sc_vtb_clear(&scp->scr, sc->scr_map[0x20],
228				     ATTR(FG_LIGHTGREY | BG_BLACK));
229			vidd_set_hw_cursor(adp, -1, -1);
230			sc_set_border(scp, 0);
231			xlen = ylen = tlen = 0;
232		}
233		if (blanked++ < 2)
234			return 0;
235		blanked = 1;
236
237 		clear_daemon(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
238		clear_string(sc, txpos, typos, toff, message, tlen);
239
240		if (++moved_daemon) {
241			/*
242			 * The daemon picture may be off the screen, if
243			 * screen size is chagened while the screen
244			 * saver is inactive. Make sure the origin of
245			 * the picture is between min and max.
246			 */
247			if (scp->xsize <= DAEMON_MAX_WIDTH) {
248				/*
249				 * If the screen width is too narrow, we
250				 * allow part of the picture go off
251				 * the screen so that the daemon won't
252				 * flip too often.
253				 */
254				min = scp->xsize - DAEMON_MAX_WIDTH - 10;
255				max = 10;
256			} else {
257				min = 0;
258				max = scp->xsize - DAEMON_MAX_WIDTH;
259			}
260			if (dxpos <= min) {
261				dxpos = min;
262				dxdir = 1;
263			} else if (dxpos >= max) {
264				dxpos = max;
265				dxdir = -1;
266			}
267
268			if (scp->ysize <= DAEMON_MAX_HEIGHT) {
269				min = scp->ysize - DAEMON_MAX_HEIGHT - 10;
270				max = 10;
271			} else {
272				min = 0;
273				max = scp->ysize - DAEMON_MAX_HEIGHT;
274			}
275			if (dypos <= min) {
276				dypos = min;
277				dydir = 1;
278			} else if (dypos >= max) {
279				dypos = max;
280				dydir = -1;
281			}
282
283			moved_daemon = -1;
284			dxpos += dxdir; dypos += dydir;
285
286			/* clip the picture */
287			xoff = 0;
288			xlen = DAEMON_MAX_WIDTH;
289			if (dxpos + xlen <= 0)
290				xlen = 0;
291			else if (dxpos < 0)
292				xoff = -dxpos;
293			if (dxpos >= scp->xsize)
294				xlen = 0;
295			else if (dxpos + xlen > scp->xsize)
296				xlen = scp->xsize - dxpos;
297			yoff = 0;
298			ylen = DAEMON_MAX_HEIGHT;
299			if (dypos + ylen <= 0)
300				ylen = 0;
301			else if (dypos < 0)
302				yoff = -dypos;
303			if (dypos >= scp->ysize)
304				ylen = 0;
305			else if (dypos + ylen > scp->ysize)
306				ylen = scp->ysize - dypos;
307		}
308
309		if (scp->xsize <= messagelen) {
310			min = scp->xsize - messagelen - 10;
311			max = 10;
312		} else {
313			min = 0;
314			max = scp->xsize - messagelen;
315		}
316		if (txpos <= min) {
317			txpos = min;
318			txdir = 1;
319		} else if (txpos >= max) {
320			txpos = max;
321			txdir = -1;
322		}
323		if (typos <= 0) {
324			typos = 0;
325			tydir = 1;
326		} else if (typos >= scp->ysize - 1) {
327			typos = scp->ysize - 1;
328			tydir = -1;
329		}
330		txpos += txdir; typos += tydir;
331
332		toff = 0;
333		tlen = messagelen;
334		if (txpos + tlen <= 0)
335			tlen = 0;
336		else if (txpos < 0)
337			toff = -txpos;
338		if (txpos >= scp->xsize)
339			tlen = 0;
340		else if (txpos + tlen > scp->xsize)
341			tlen = scp->xsize - txpos;
342
343 		draw_daemon(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
344		draw_string(sc, txpos, typos, toff, message, tlen);
345	} else
346		blanked = 0;
347
348	return 0;
349}
350
351static int
352daemon_init(video_adapter_t *adp)
353{
354	size_t hostlen;
355
356	mtx_lock(&prison0.pr_mtx);
357	for (;;) {
358		hostlen = strlen(prison0.pr_hostname);
359		mtx_unlock(&prison0.pr_mtx);
360
361		messagelen = hostlen + 3 + strlen(ostype) + 1 +
362		    strlen(osrelease);
363		message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK);
364		mtx_lock(&prison0.pr_mtx);
365		if (hostlen < strlen(prison0.pr_hostname)) {
366			free(message, M_DEVBUF);
367			continue;
368		}
369		break;
370	}
371	sprintf(message, "%s - %s %s", prison0.pr_hostname, ostype, osrelease);
372	mtx_unlock(&prison0.pr_mtx);
373	blanked = 0;
374	switch (adp->va_mode) {
375	case M_PC98_80x25:
376	case M_PC98_80x30:
377		attr_mask = ~FG_UNDERLINE;
378		break;
379	default:
380		attr_mask = ~0;
381		break;
382	}
383
384	return 0;
385}
386
387static int
388daemon_term(video_adapter_t *adp)
389{
390	free(message, M_DEVBUF);
391	return 0;
392}
393
394static scrn_saver_t daemon_module = {
395	"daemon_saver", daemon_init, daemon_term, daemon_saver, NULL,
396};
397
398SAVER_MODULE(daemon_saver, daemon_module);
399