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