1 /*- 2 * (MPSAFE) 3 * 4 * Copyright (c) 1997 Sandro Sigala, Brescia, Italy. 5 * Copyright (c) 1997 Chris Shenton 6 * Copyright (c) 1995 S ren Schmidt 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer 14 * in this position and unchanged. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $FreeBSD: src/sys/modules/syscons/daemon/daemon_saver.c,v 1.18.2.2 2001/05/06 05:44:29 nyan Exp $ 31 * $DragonFly: src/sys/dev/misc/syscons/fred/fred_saver.c,v 1.8 2007/08/09 02:27:51 swildner Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/module.h> 37 #include <sys/malloc.h> 38 #include <sys/kernel.h> 39 #include <sys/sysctl.h> 40 #include <sys/consio.h> 41 #include <sys/fbio.h> 42 #include <sys/thread.h> 43 44 #include <machine/pc/display.h> 45 46 #include <dev/video/fb/fbreg.h> 47 #include <dev/video/fb/splashreg.h> 48 #include "../syscons.h" 49 50 #define FRED_MAX_WIDTH 31 51 #define FRED_MAX_HEIGHT 15 52 53 static char *message; 54 static int messagelen; 55 static int blanked; 56 57 static const char *fred_pic[] = { 58 ",--, | ,--,", 59 "| `-, ,^, ,-' |", 60 " `, `-, (/ \\) ,-' ,'", 61 " `-, `-,/ \\,-' ,-'", 62 " `------( )------'", 63 " ,----------( )----------,", 64 " | _,-( )-,_ |", 65 " `-,__,-' \\ / `-,__,-'", 66 " | |", 67 " | |", 68 " | |", 69 " | |", 70 " | |", 71 " | |", 72 " `|'", 73 NULL 74 }; 75 76 static const char *fred_attr[] = { 77 "WWWW R WWWW", 78 "W WWW RRR WWW W", 79 " WW WWW GR RG WWW WW ", 80 " WWW WWWR RWWW WWW", 81 " WWWWWWWR RWWWWWWW", 82 " WWWWWWWWWWWR RWWWWWWWWWWW", 83 " W WWWR RWWW W", 84 " WWWWWWWW R R WWWWWWWW", 85 " R R", 86 " R R", 87 " R R", 88 " R R", 89 " R R", 90 " R R", 91 " RRR", 92 NULL 93 }; 94 95 /* 96 * Reverse a graphics character, or return unaltered if no mirror; 97 * should do alphanumerics too, but I'm too lazy. <cshenton@it.hq.nasa.gov> 98 */ 99 100 static u_char 101 xflip_symbol(u_char symbol) 102 { 103 static const u_char lchars[] = "`'(){}[]\\/<>"; 104 static const u_char rchars[] = "'`)(}{][/\\><"; 105 int pos; 106 107 for (pos = 0; lchars[pos] != '\0'; pos++) 108 if (lchars[pos] == symbol) 109 return rchars[pos]; 110 111 return symbol; 112 } 113 114 static void 115 clear_fred(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff, 116 int xlen, int ylen) 117 { 118 int y; 119 120 if (xlen <= 0) 121 return; 122 123 for (y = yoff; y < ylen; y++) { 124 sc_vtb_erase(&sc->cur_scp->scr, 125 (ypos + y)*sc->cur_scp->xsize + xpos + xoff, 126 xlen - xoff, 127 sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8); 128 } 129 } 130 131 static void 132 draw_fred(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff, 133 int xlen, int ylen) 134 { 135 int x, y; 136 int px; 137 int attr; 138 139 for (y = yoff; y < ylen; y++) { 140 if (dxdir < 0) 141 px = xoff; 142 else 143 px = FRED_MAX_WIDTH - xlen; 144 if (px >= strlen(fred_pic[y])) 145 continue; 146 for (x = xoff; (x < xlen) && (fred_pic[y][px] != '\0'); x++, px++) { 147 switch (fred_attr[y][px]) { 148 case 'R': attr = (FG_LIGHTRED|BG_BLACK)<<8; break; 149 case 'G': attr = (FG_LIGHTGREEN|BG_BLACK)<<8; break; 150 case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break; 151 default: attr = (FG_WHITE|BG_BLACK)<<8; break; 152 } 153 if (dxdir < 0) { /* Moving left */ 154 sc_vtb_putc(&sc->cur_scp->scr, 155 (ypos + y)*sc->cur_scp->xsize 156 + xpos + x, 157 sc->scr_map[(int)fred_pic[y][px]], 158 attr); 159 } else { /* Moving right */ 160 sc_vtb_putc(&sc->cur_scp->scr, 161 (ypos + y)*sc->cur_scp->xsize 162 + xpos + FRED_MAX_WIDTH 163 - px - 1, 164 sc->scr_map[xflip_symbol(fred_pic[y][px])], 165 attr); 166 } 167 } 168 } 169 } 170 171 static void 172 clear_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 173 { 174 if (len <= 0) 175 return; 176 sc_vtb_erase(&sc->cur_scp->scr, 177 ypos*sc->cur_scp->xsize + xpos + xoff, len - xoff, 178 sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8); 179 } 180 181 static void 182 draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 183 { 184 int x; 185 186 for (x = xoff; x < len; x++) { 187 sc_vtb_putc(&sc->cur_scp->scr, 188 ypos*sc->cur_scp->xsize + xpos + x, 189 sc->scr_map[(int)s[x]], (FG_LIGHTBLUE | BG_BLACK) << 8); 190 } 191 } 192 193 static int 194 fred_saver(video_adapter_t *adp, int blank) 195 { 196 static int txpos = 10, typos = 10; 197 static int txdir = -1, tydir = -1; 198 static int dxpos = 0, dypos = 0; 199 static int dxdir = 1, dydir = 1; 200 static int moved_fred = 0; 201 static int xoff, yoff, toff; 202 static int xlen, ylen, tlen; 203 sc_softc_t *sc; 204 scr_stat *scp; 205 int min, max; 206 207 sc = sc_find_softc(adp, NULL); 208 if (sc == NULL) { 209 return EAGAIN; 210 } 211 scp = sc->cur_scp; 212 213 if (blank) { 214 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) { 215 return EAGAIN; 216 } 217 if (blanked == 0) { 218 /* clear the screen and set the border color */ 219 sc_vtb_clear(&scp->scr, sc->scr_map[0x20], 220 (FG_LIGHTGREY | BG_BLACK) << 8); 221 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 222 sc_set_border(scp, 0); 223 xlen = ylen = tlen = 0; 224 } 225 if (blanked++ < 2) { 226 return 0; 227 } 228 blanked = 1; 229 230 clear_fred(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 231 clear_string(sc, txpos, typos, toff, message, tlen); 232 233 if (++moved_fred) { 234 /* 235 * Fred's picture may be off the screen, if 236 * screen size is chagened while the screen 237 * saver is inactive. Make sure the origin of 238 * the picture is between min and max. 239 */ 240 if (scp->xsize <= FRED_MAX_WIDTH) { 241 /* 242 * If the screen width is too narrow, we 243 * allow part of the picture go off 244 * the screen so that Fred won't 245 * flip too often. 246 */ 247 min = scp->xsize - FRED_MAX_WIDTH - 10; 248 max = 10; 249 } else { 250 min = 0; 251 max = scp->xsize - FRED_MAX_WIDTH; 252 } 253 if (dxpos <= min) { 254 dxpos = min; 255 dxdir = 1; 256 } else if (dxpos >= max) { 257 dxpos = max; 258 dxdir = -1; 259 } 260 261 if (scp->ysize <= FRED_MAX_HEIGHT) { 262 min = scp->ysize - FRED_MAX_HEIGHT - 10; 263 max = 10; 264 } else { 265 min = 0; 266 max = scp->ysize - FRED_MAX_HEIGHT; 267 } 268 if (dypos <= min) { 269 dypos = min; 270 dydir = 1; 271 } else if (dypos >= max) { 272 dypos = max; 273 dydir = -1; 274 } 275 276 moved_fred = -1; 277 dxpos += dxdir; dypos += dydir; 278 279 /* clip the picture */ 280 xoff = 0; 281 xlen = FRED_MAX_WIDTH; 282 if (dxpos + xlen <= 0) 283 xlen = 0; 284 else if (dxpos < 0) 285 xoff = -dxpos; 286 if (dxpos >= scp->xsize) 287 xlen = 0; 288 else if (dxpos + xlen > scp->xsize) 289 xlen = scp->xsize - dxpos; 290 yoff = 0; 291 ylen = FRED_MAX_HEIGHT; 292 if (dypos + ylen <= 0) 293 ylen = 0; 294 else if (dypos < 0) 295 yoff = -dypos; 296 if (dypos >= scp->ysize) 297 ylen = 0; 298 else if (dypos + ylen > scp->ysize) 299 ylen = scp->ysize - dypos; 300 } 301 302 if (scp->xsize <= messagelen) { 303 min = scp->xsize - messagelen - 10; 304 max = 10; 305 } else { 306 min = 0; 307 max = scp->xsize - messagelen; 308 } 309 if (txpos <= min) { 310 txpos = min; 311 txdir = 1; 312 } else if (txpos >= max) { 313 txpos = max; 314 txdir = -1; 315 } 316 if (typos <= 0) { 317 typos = 0; 318 tydir = 1; 319 } else if (typos >= scp->ysize - 1) { 320 typos = scp->ysize - 1; 321 tydir = -1; 322 } 323 txpos += txdir; typos += tydir; 324 325 toff = 0; 326 tlen = messagelen; 327 if (txpos + tlen <= 0) 328 tlen = 0; 329 else if (txpos < 0) 330 toff = -txpos; 331 if (txpos >= scp->xsize) 332 tlen = 0; 333 else if (txpos + tlen > scp->xsize) 334 tlen = scp->xsize - txpos; 335 336 draw_fred(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 337 draw_string(sc, txpos, typos, toff, message, tlen); 338 } else { 339 blanked = 0; 340 } 341 return 0; 342 } 343 344 static int 345 fred_init(video_adapter_t *adp) 346 { 347 messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 + 348 strlen(osrelease); 349 message = kmalloc(messagelen + 1, M_SYSCONS, M_WAITOK); 350 ksprintf(message, "%s - %s %s", hostname, ostype, osrelease); 351 blanked = 0; 352 return 0; 353 } 354 355 static int 356 fred_term(video_adapter_t *adp) 357 { 358 kfree(message, M_SYSCONS); 359 return 0; 360 } 361 362 static scrn_saver_t fred_module = { 363 "fred_saver", fred_init, fred_term, fred_saver, NULL, 364 }; 365 366 SAVER_MODULE(fred_saver, fred_module); 367