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