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 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 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 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 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 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 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 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 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