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