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