1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
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
50 static u_char *message;
51 static int messagelen;
52 static int blanked;
53 static int attr_mask;
54
55 #define ATTR(attr) (((attr) & attr_mask) << 8)
56
57 /* Who is the author of this ASCII pic? */
58
59 static 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
82 static 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
110 static u_char
xflip_symbol(u_char symbol)111 xflip_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
124 static void
clear_daemon(sc_softc_t * sc,int xpos,int ypos,int dxdir,int xoff,int yoff,int xlen,int ylen)125 clear_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
140 static void
draw_daemon(sc_softc_t * sc,int xpos,int ypos,int dxdir,int xoff,int yoff,int xlen,int ylen)141 draw_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
182 static void
clear_string(sc_softc_t * sc,int xpos,int ypos,int xoff,char * s,int len)183 clear_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
192 static void
draw_string(sc_softc_t * sc,int xpos,int ypos,int xoff,u_char * s,int len)193 draw_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
203 static int
daemon_saver(video_adapter_t * adp,int blank)204 daemon_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
351 static int
daemon_init(video_adapter_t * adp)352 daemon_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 attr_mask = ~0;
375
376 return 0;
377 }
378
379 static int
daemon_term(video_adapter_t * adp)380 daemon_term(video_adapter_t *adp)
381 {
382 free(message, M_DEVBUF);
383 return 0;
384 }
385
386 static scrn_saver_t daemon_module = {
387 "daemon_saver", daemon_init, daemon_term, daemon_saver, NULL,
388 };
389
390 SAVER_MODULE(daemon_saver, daemon_module);
391