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$ 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/kernel.h> 36 #include <sys/sysctl.h> 37 #include <sys/consio.h> 38 #include <sys/fbio.h> 39 40 #include <machine/pc/display.h> 41 42 #include <dev/fb/fbreg.h> 43 #include <dev/fb/splashreg.h> 44 #include <dev/syscons/syscons.h> 45 46 #define DAEMON_MAX_WIDTH 32 47 #define DAEMON_MAX_HEIGHT 19 48 49 static u_char *message; 50 static int messagelen; 51 static int blanked; 52 static int attr_mask; 53 54 #define ATTR(attr) (((attr) & attr_mask) << 8) 55 56 /* Who is the author of this ASCII pic? */ 57 58 static u_char *daemon_pic[] = { 59 " , ,", 60 " /( )`", 61 " \\ \\___ / |", 62 " /- _ `-/ '", 63 " (/\\/ \\ \\ /\\", 64 " / / | ` \\", 65 " O O ) / |", 66 " `-^--'`< '", 67 " (_.) _ ) /", 68 " `.___/` /", 69 " `-----' /", 70 "<----. __ / __ \\", 71 "<----|====O)))==) \\) /====", 72 "<----' `--' `.__,' \\", 73 " | |", 74 " \\ / /\\", 75 " ______( (_ / \\______/", 76 " ,' ,-----' |", 77 " `--{__________)", 78 NULL 79 }; 80 81 static u_char *daemon_attr[] = { 82 " R R", 83 " RR RR", 84 " R RRRR R R", 85 " RR W RRR R", 86 " RWWW W R RR", 87 " W W W R R", 88 " B B W R R", 89 " WWWWWWRR R", 90 " RRRR R R R", 91 " RRRRRRR R", 92 " RRRRRRR R", 93 "YYYYYY RR R RR R", 94 "YYYYYYYYYYRRRRYYR RR RYYYY", 95 "YYYYYY RRRR RRRRRR R", 96 " R R", 97 " R R RR", 98 " CCCCCCR RR R RRRRRRRR", 99 " CC CCCCCCC C", 100 " CCCCCCCCCCCCCCC", 101 NULL 102 }; 103 104 /* 105 * Reverse a graphics character, or return unaltered if no mirror; 106 * should do alphanumerics too, but I'm too lazy. <cshenton@it.hq.nasa.gov> 107 */ 108 109 static u_char 110 xflip_symbol(u_char symbol) 111 { 112 static const u_char lchars[] = "`'(){}[]\\/<>"; 113 static const u_char rchars[] = "'`)(}{][/\\><"; 114 int pos; 115 116 for (pos = 0; lchars[pos] != '\0'; pos++) 117 if (lchars[pos] == symbol) 118 return rchars[pos]; 119 120 return symbol; 121 } 122 123 static void 124 clear_daemon(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff, 125 int xlen, int ylen) 126 { 127 int y; 128 129 if (xlen <= 0) 130 return; 131 for (y = yoff; y < ylen; y++) { 132 sc_vtb_erase(&sc->cur_scp->scr, 133 (ypos + y)*sc->cur_scp->xsize + xpos + xoff, 134 xlen - xoff, 135 sc->scr_map[0x20], ATTR(FG_LIGHTGREY | BG_BLACK)); 136 } 137 } 138 139 static void 140 draw_daemon(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff, 141 int xlen, int ylen) 142 { 143 int x, y; 144 int px; 145 int attr; 146 147 for (y = yoff; y < ylen; y++) { 148 if (dxdir < 0) 149 px = xoff; 150 else 151 px = DAEMON_MAX_WIDTH - xlen; 152 if (px >= strlen(daemon_pic[y])) 153 continue; 154 for (x = xoff; (x < xlen) && (daemon_pic[y][px] != '\0'); x++, px++) { 155 switch (daemon_attr[y][px]) { 156 case 'R': attr = FG_LIGHTRED | BG_BLACK; break; 157 case 'Y': attr = FG_YELLOW | BG_BLACK; break; 158 case 'B': attr = FG_LIGHTBLUE | BG_BLACK; break; 159 case 'W': attr = FG_LIGHTGREY | BG_BLACK; break; 160 case 'C': attr = FG_CYAN | BG_BLACK; break; 161 default: attr = FG_WHITE | BG_BLACK; break; 162 } 163 if (dxdir < 0) { /* Moving left */ 164 sc_vtb_putc(&sc->cur_scp->scr, 165 (ypos + y)*sc->cur_scp->xsize 166 + xpos + x, 167 sc->scr_map[daemon_pic[y][px]], 168 ATTR(attr)); 169 } else { /* Moving right */ 170 sc_vtb_putc(&sc->cur_scp->scr, 171 (ypos + y)*sc->cur_scp->xsize 172 + xpos + DAEMON_MAX_WIDTH 173 - px - 1, 174 sc->scr_map[xflip_symbol(daemon_pic[y][px])], 175 ATTR(attr)); 176 } 177 } 178 } 179 } 180 181 static void 182 clear_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 183 { 184 if (len <= 0) 185 return; 186 sc_vtb_erase(&sc->cur_scp->scr, 187 ypos*sc->cur_scp->xsize + xpos + xoff, len - xoff, 188 sc->scr_map[0x20], ATTR(FG_LIGHTGREY | BG_BLACK)); 189 } 190 191 static void 192 draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, u_char *s, int len) 193 { 194 int x; 195 196 for (x = xoff; x < len; x++) 197 sc_vtb_putc(&sc->cur_scp->scr, 198 ypos*sc->cur_scp->xsize + xpos + x, 199 sc->scr_map[s[x]], ATTR(FG_LIGHTGREEN | BG_BLACK)); 200 } 201 202 static int 203 daemon_saver(video_adapter_t *adp, int blank) 204 { 205 static int txpos = 10, typos = 10; 206 static int txdir = -1, tydir = -1; 207 static int dxpos = 0, dypos = 0; 208 static int dxdir = 1, dydir = 1; 209 static int moved_daemon = 0; 210 static int xoff, yoff, toff; 211 static int xlen, ylen, tlen; 212 sc_softc_t *sc; 213 scr_stat *scp; 214 int min, max; 215 216 sc = sc_find_softc(adp, NULL); 217 if (sc == NULL) 218 return EAGAIN; 219 scp = sc->cur_scp; 220 221 if (blank) { 222 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 223 return EAGAIN; 224 if (blanked == 0) { 225 /* clear the screen and set the border color */ 226 sc_vtb_clear(&scp->scr, sc->scr_map[0x20], 227 ATTR(FG_LIGHTGREY | BG_BLACK)); 228 vidd_set_hw_cursor(adp, -1, -1); 229 sc_set_border(scp, 0); 230 xlen = ylen = tlen = 0; 231 } 232 if (blanked++ < 2) 233 return 0; 234 blanked = 1; 235 236 clear_daemon(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 237 clear_string(sc, txpos, typos, toff, message, tlen); 238 239 if (++moved_daemon) { 240 /* 241 * The daemon picture may be off the screen, if 242 * screen size is chagened while the screen 243 * saver is inactive. Make sure the origin of 244 * the picture is between min and max. 245 */ 246 if (scp->xsize <= DAEMON_MAX_WIDTH) { 247 /* 248 * If the screen width is too narrow, we 249 * allow part of the picture go off 250 * the screen so that the daemon won't 251 * flip too often. 252 */ 253 min = scp->xsize - DAEMON_MAX_WIDTH - 10; 254 max = 10; 255 } else { 256 min = 0; 257 max = scp->xsize - DAEMON_MAX_WIDTH; 258 } 259 if (dxpos <= min) { 260 dxpos = min; 261 dxdir = 1; 262 } else if (dxpos >= max) { 263 dxpos = max; 264 dxdir = -1; 265 } 266 267 if (scp->ysize <= DAEMON_MAX_HEIGHT) { 268 min = scp->ysize - DAEMON_MAX_HEIGHT - 10; 269 max = 10; 270 } else { 271 min = 0; 272 max = scp->ysize - DAEMON_MAX_HEIGHT; 273 } 274 if (dypos <= min) { 275 dypos = min; 276 dydir = 1; 277 } else if (dypos >= max) { 278 dypos = max; 279 dydir = -1; 280 } 281 282 moved_daemon = -1; 283 dxpos += dxdir; dypos += dydir; 284 285 /* clip the picture */ 286 xoff = 0; 287 xlen = DAEMON_MAX_WIDTH; 288 if (dxpos + xlen <= 0) 289 xlen = 0; 290 else if (dxpos < 0) 291 xoff = -dxpos; 292 if (dxpos >= scp->xsize) 293 xlen = 0; 294 else if (dxpos + xlen > scp->xsize) 295 xlen = scp->xsize - dxpos; 296 yoff = 0; 297 ylen = DAEMON_MAX_HEIGHT; 298 if (dypos + ylen <= 0) 299 ylen = 0; 300 else if (dypos < 0) 301 yoff = -dypos; 302 if (dypos >= scp->ysize) 303 ylen = 0; 304 else if (dypos + ylen > scp->ysize) 305 ylen = scp->ysize - dypos; 306 } 307 308 if (scp->xsize <= messagelen) { 309 min = scp->xsize - messagelen - 10; 310 max = 10; 311 } else { 312 min = 0; 313 max = scp->xsize - messagelen; 314 } 315 if (txpos <= min) { 316 txpos = min; 317 txdir = 1; 318 } else if (txpos >= max) { 319 txpos = max; 320 txdir = -1; 321 } 322 if (typos <= 0) { 323 typos = 0; 324 tydir = 1; 325 } else if (typos >= scp->ysize - 1) { 326 typos = scp->ysize - 1; 327 tydir = -1; 328 } 329 txpos += txdir; typos += tydir; 330 331 toff = 0; 332 tlen = messagelen; 333 if (txpos + tlen <= 0) 334 tlen = 0; 335 else if (txpos < 0) 336 toff = -txpos; 337 if (txpos >= scp->xsize) 338 tlen = 0; 339 else if (txpos + tlen > scp->xsize) 340 tlen = scp->xsize - txpos; 341 342 draw_daemon(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 343 draw_string(sc, txpos, typos, toff, message, tlen); 344 } else 345 blanked = 0; 346 347 return 0; 348 } 349 350 static int 351 daemon_init(video_adapter_t *adp) 352 { 353 messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 + 354 strlen(osrelease); 355 message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK); 356 sprintf(message, "%s - %s %s", hostname, ostype, osrelease); 357 blanked = 0; 358 switch (adp->va_mode) { 359 case M_PC98_80x25: 360 case M_PC98_80x30: 361 attr_mask = ~FG_UNDERLINE; 362 break; 363 default: 364 attr_mask = ~0; 365 break; 366 } 367 368 return 0; 369 } 370 371 static int 372 daemon_term(video_adapter_t *adp) 373 { 374 free(message, M_DEVBUF); 375 return 0; 376 } 377 378 static scrn_saver_t daemon_module = { 379 "daemon_saver", daemon_init, daemon_term, daemon_saver, NULL, 380 }; 381 382 SAVER_MODULE(daemon_saver, daemon_module); 383