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