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 #ifdef PC98 47 #include <pc98/pc98/pc98_machdep.h> 48 #endif 49 50 #define DAEMON_MAX_WIDTH 32 51 #define DAEMON_MAX_HEIGHT 19 52 53 static char *message; 54 static int messagelen; 55 static int blanked; 56 57 /* Who is the author of this ASCII pic? */ 58 59 static 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 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 char 111 xflip_symbol(char symbol) 112 { 113 static const char lchars[] = "`'(){}[]\\/<>"; 114 static const 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], (FG_LIGHTGREY | BG_BLACK) << 8); 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 #ifndef PC98 158 case 'R': attr = (FG_LIGHTRED|BG_BLACK)<<8; break; 159 case 'Y': attr = (FG_YELLOW|BG_BLACK)<<8; break; 160 case 'B': attr = (FG_LIGHTBLUE|BG_BLACK)<<8; break; 161 case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break; 162 case 'C': attr = (FG_CYAN|BG_BLACK)<<8; break; 163 default: attr = (FG_WHITE|BG_BLACK)<<8; break; 164 #else /* PC98 */ 165 case 'R': attr = (FG_RED|BG_BLACK)<<8; break; 166 case 'Y': attr = (FG_BROWN|BG_BLACK)<<8; break; 167 case 'B': attr = (FG_BLUE|BG_BLACK)<<8; break; 168 case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break; 169 case 'C': attr = (FG_CYAN|BG_BLACK)<<8; break; 170 default: attr = (FG_LIGHTGREY|BG_BLACK)<<8; break; 171 #endif /* PC98 */ 172 } 173 if (dxdir < 0) { /* Moving left */ 174 sc_vtb_putc(&sc->cur_scp->scr, 175 (ypos + y)*sc->cur_scp->xsize 176 + xpos + x, 177 sc->scr_map[daemon_pic[y][px]], 178 attr); 179 } else { /* Moving right */ 180 sc_vtb_putc(&sc->cur_scp->scr, 181 (ypos + y)*sc->cur_scp->xsize 182 + xpos + DAEMON_MAX_WIDTH 183 - px - 1, 184 sc->scr_map[xflip_symbol(daemon_pic[y][px])], 185 attr); 186 } 187 } 188 } 189 } 190 191 static void 192 clear_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 193 { 194 if (len <= 0) 195 return; 196 sc_vtb_erase(&sc->cur_scp->scr, 197 ypos*sc->cur_scp->xsize + xpos + xoff, len - xoff, 198 sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8); 199 } 200 201 static void 202 draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 203 { 204 int x; 205 206 for (x = xoff; x < len; x++) { 207 #ifdef PC98 208 sc_vtb_putc(&sc->cur_scp->scr, 209 ypos*sc->cur_scp->xsize + xpos + x, 210 sc->scr_map[s[x]], (FG_GREEN | BG_BLACK) << 8); 211 #else 212 sc_vtb_putc(&sc->cur_scp->scr, 213 ypos*sc->cur_scp->xsize + xpos + x, 214 sc->scr_map[s[x]], (FG_LIGHTGREEN | BG_BLACK) << 8); 215 #endif 216 } 217 } 218 219 static int 220 daemon_saver(video_adapter_t *adp, int blank) 221 { 222 static int txpos = 10, typos = 10; 223 static int txdir = -1, tydir = -1; 224 static int dxpos = 0, dypos = 0; 225 static int dxdir = 1, dydir = 1; 226 static int moved_daemon = 0; 227 static int xoff, yoff, toff; 228 static int xlen, ylen, tlen; 229 sc_softc_t *sc; 230 scr_stat *scp; 231 int min, max; 232 233 sc = sc_find_softc(adp, NULL); 234 if (sc == NULL) 235 return EAGAIN; 236 scp = sc->cur_scp; 237 238 if (blank) { 239 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 240 return EAGAIN; 241 if (blanked == 0) { 242 #ifdef PC98 243 if (epson_machine_id == 0x20) { 244 outb(0x43f, 0x42); 245 outb(0x0c17, inb(0xc17) & ~0x08); 246 outb(0x43f, 0x40); 247 } 248 #endif /* PC98 */ 249 /* clear the screen and set the border color */ 250 sc_vtb_clear(&scp->scr, sc->scr_map[0x20], 251 (FG_LIGHTGREY | BG_BLACK) << 8); 252 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 253 sc_set_border(scp, 0); 254 xlen = ylen = tlen = 0; 255 } 256 if (blanked++ < 2) 257 return 0; 258 blanked = 1; 259 260 clear_daemon(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 261 clear_string(sc, txpos, typos, toff, (char *)message, tlen); 262 263 if (++moved_daemon) { 264 /* 265 * The daemon picture may be off the screen, if 266 * screen size is chagened while the screen 267 * saver is inactive. Make sure the origin of 268 * the picture is between min and max. 269 */ 270 if (scp->xsize <= DAEMON_MAX_WIDTH) { 271 /* 272 * If the screen width is too narrow, we 273 * allow part of the picture go off 274 * the screen so that the daemon won't 275 * flip too often. 276 */ 277 min = scp->xsize - DAEMON_MAX_WIDTH - 10; 278 max = 10; 279 } else { 280 min = 0; 281 max = scp->xsize - DAEMON_MAX_WIDTH; 282 } 283 if (dxpos <= min) { 284 dxpos = min; 285 dxdir = 1; 286 } else if (dxpos >= max) { 287 dxpos = max; 288 dxdir = -1; 289 } 290 291 if (scp->ysize <= DAEMON_MAX_HEIGHT) { 292 min = scp->ysize - DAEMON_MAX_HEIGHT - 10; 293 max = 10; 294 } else { 295 min = 0; 296 max = scp->ysize - DAEMON_MAX_HEIGHT; 297 } 298 if (dypos <= min) { 299 dypos = min; 300 dydir = 1; 301 } else if (dypos >= max) { 302 dypos = max; 303 dydir = -1; 304 } 305 306 moved_daemon = -1; 307 dxpos += dxdir; dypos += dydir; 308 309 /* clip the picture */ 310 xoff = 0; 311 xlen = DAEMON_MAX_WIDTH; 312 if (dxpos + xlen <= 0) 313 xlen = 0; 314 else if (dxpos < 0) 315 xoff = -dxpos; 316 if (dxpos >= scp->xsize) 317 xlen = 0; 318 else if (dxpos + xlen > scp->xsize) 319 xlen = scp->xsize - dxpos; 320 yoff = 0; 321 ylen = DAEMON_MAX_HEIGHT; 322 if (dypos + ylen <= 0) 323 ylen = 0; 324 else if (dypos < 0) 325 yoff = -dypos; 326 if (dypos >= scp->ysize) 327 ylen = 0; 328 else if (dypos + ylen > scp->ysize) 329 ylen = scp->ysize - dypos; 330 } 331 332 if (scp->xsize <= messagelen) { 333 min = scp->xsize - messagelen - 10; 334 max = 10; 335 } else { 336 min = 0; 337 max = scp->xsize - messagelen; 338 } 339 if (txpos <= min) { 340 txpos = min; 341 txdir = 1; 342 } else if (txpos >= max) { 343 txpos = max; 344 txdir = -1; 345 } 346 if (typos <= 0) { 347 typos = 0; 348 tydir = 1; 349 } else if (typos >= scp->ysize - 1) { 350 typos = scp->ysize - 1; 351 tydir = -1; 352 } 353 txpos += txdir; typos += tydir; 354 355 toff = 0; 356 tlen = messagelen; 357 if (txpos + tlen <= 0) 358 tlen = 0; 359 else if (txpos < 0) 360 toff = -txpos; 361 if (txpos >= scp->xsize) 362 tlen = 0; 363 else if (txpos + tlen > scp->xsize) 364 tlen = scp->xsize - txpos; 365 366 draw_daemon(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 367 draw_string(sc, txpos, typos, toff, (char *)message, tlen); 368 } else { 369 #ifdef PC98 370 if (epson_machine_id == 0x20) { 371 outb(0x43f, 0x42); 372 outb(0x0c17, inb(0xc17) | 0x08); 373 outb(0x43f, 0x40); 374 } 375 #endif /* PC98 */ 376 blanked = 0; 377 } 378 return 0; 379 } 380 381 static int 382 daemon_init(video_adapter_t *adp) 383 { 384 messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 + 385 strlen(osrelease); 386 message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK); 387 sprintf(message, "%s - %s %s", hostname, ostype, osrelease); 388 blanked = 0; 389 return 0; 390 } 391 392 static int 393 daemon_term(video_adapter_t *adp) 394 { 395 free(message, M_DEVBUF); 396 return 0; 397 } 398 399 static scrn_saver_t daemon_module = { 400 "daemon_saver", daemon_init, daemon_term, daemon_saver, NULL, 401 }; 402 403 SAVER_MODULE(daemon_saver, daemon_module); 404