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.8 2007/08/09 02:27:51 swildner 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 FRED_MAX_WIDTH 31 48 #define FRED_MAX_HEIGHT 15 49 50 static char *message; 51 static int messagelen; 52 static int blanked; 53 54 static const char *fred_pic[] = { 55 ",--, | ,--,", 56 "| `-, ,^, ,-' |", 57 " `, `-, (/ \\) ,-' ,'", 58 " `-, `-,/ \\,-' ,-'", 59 " `------( )------'", 60 " ,----------( )----------,", 61 " | _,-( )-,_ |", 62 " `-,__,-' \\ / `-,__,-'", 63 " | |", 64 " | |", 65 " | |", 66 " | |", 67 " | |", 68 " | |", 69 " `|'", 70 NULL 71 }; 72 73 static const char *fred_attr[] = { 74 "WWWW R WWWW", 75 "W WWW RRR WWW W", 76 " WW WWW GR RG WWW WW ", 77 " WWW WWWR RWWW WWW", 78 " WWWWWWWR RWWWWWWW", 79 " WWWWWWWWWWWR RWWWWWWWWWWW", 80 " W WWWR RWWW W", 81 " WWWWWWWW R R WWWWWWWW", 82 " R R", 83 " R R", 84 " R R", 85 " R R", 86 " R R", 87 " R R", 88 " RRR", 89 NULL 90 }; 91 92 /* 93 * Reverse a graphics character, or return unaltered if no mirror; 94 * should do alphanumerics too, but I'm too lazy. <cshenton@it.hq.nasa.gov> 95 */ 96 97 static u_char 98 xflip_symbol(u_char symbol) 99 { 100 static const u_char lchars[] = "`'(){}[]\\/<>"; 101 static const u_char rchars[] = "'`)(}{][/\\><"; 102 int pos; 103 104 for (pos = 0; lchars[pos] != '\0'; pos++) 105 if (lchars[pos] == symbol) 106 return rchars[pos]; 107 108 return symbol; 109 } 110 111 static void 112 clear_fred(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff, 113 int xlen, int ylen) 114 { 115 int y; 116 117 if (xlen <= 0) 118 return; 119 for (y = yoff; y < ylen; y++) { 120 sc_vtb_erase(&sc->cur_scp->scr, 121 (ypos + y)*sc->cur_scp->xsize + xpos + xoff, 122 xlen - xoff, 123 sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8); 124 } 125 } 126 127 static void 128 draw_fred(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff, 129 int xlen, int ylen) 130 { 131 int x, y; 132 int px; 133 int attr; 134 135 for (y = yoff; y < ylen; y++) { 136 if (dxdir < 0) 137 px = xoff; 138 else 139 px = FRED_MAX_WIDTH - xlen; 140 if (px >= strlen(fred_pic[y])) 141 continue; 142 for (x = xoff; (x < xlen) && (fred_pic[y][px] != '\0'); x++, px++) { 143 switch (fred_attr[y][px]) { 144 case 'R': attr = (FG_LIGHTRED|BG_BLACK)<<8; break; 145 case 'G': attr = (FG_LIGHTGREEN|BG_BLACK)<<8; break; 146 case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break; 147 default: attr = (FG_WHITE|BG_BLACK)<<8; break; 148 } 149 if (dxdir < 0) { /* Moving left */ 150 sc_vtb_putc(&sc->cur_scp->scr, 151 (ypos + y)*sc->cur_scp->xsize 152 + xpos + x, 153 sc->scr_map[(int)fred_pic[y][px]], 154 attr); 155 } else { /* Moving right */ 156 sc_vtb_putc(&sc->cur_scp->scr, 157 (ypos + y)*sc->cur_scp->xsize 158 + xpos + FRED_MAX_WIDTH 159 - px - 1, 160 sc->scr_map[xflip_symbol(fred_pic[y][px])], 161 attr); 162 } 163 } 164 } 165 } 166 167 static void 168 clear_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 169 { 170 if (len <= 0) 171 return; 172 sc_vtb_erase(&sc->cur_scp->scr, 173 ypos*sc->cur_scp->xsize + xpos + xoff, len - xoff, 174 sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8); 175 } 176 177 static void 178 draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len) 179 { 180 int x; 181 182 for (x = xoff; x < len; x++) { 183 sc_vtb_putc(&sc->cur_scp->scr, 184 ypos*sc->cur_scp->xsize + xpos + x, 185 sc->scr_map[(int)s[x]], (FG_LIGHTBLUE | BG_BLACK) << 8); 186 } 187 } 188 189 static int 190 fred_saver(video_adapter_t *adp, int blank) 191 { 192 static int txpos = 10, typos = 10; 193 static int txdir = -1, tydir = -1; 194 static int dxpos = 0, dypos = 0; 195 static int dxdir = 1, dydir = 1; 196 static int moved_fred = 0; 197 static int xoff, yoff, toff; 198 static int xlen, ylen, tlen; 199 sc_softc_t *sc; 200 scr_stat *scp; 201 int min, max; 202 203 sc = sc_find_softc(adp, NULL); 204 if (sc == NULL) 205 return EAGAIN; 206 scp = sc->cur_scp; 207 208 if (blank) { 209 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 210 return EAGAIN; 211 if (blanked == 0) { 212 /* clear the screen and set the border color */ 213 sc_vtb_clear(&scp->scr, sc->scr_map[0x20], 214 (FG_LIGHTGREY | BG_BLACK) << 8); 215 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 216 sc_set_border(scp, 0); 217 xlen = ylen = tlen = 0; 218 } 219 if (blanked++ < 2) 220 return 0; 221 blanked = 1; 222 223 clear_fred(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 224 clear_string(sc, txpos, typos, toff, message, tlen); 225 226 if (++moved_fred) { 227 /* 228 * Fred's picture may be off the screen, if 229 * screen size is chagened while the screen 230 * saver is inactive. Make sure the origin of 231 * the picture is between min and max. 232 */ 233 if (scp->xsize <= FRED_MAX_WIDTH) { 234 /* 235 * If the screen width is too narrow, we 236 * allow part of the picture go off 237 * the screen so that Fred won't 238 * flip too often. 239 */ 240 min = scp->xsize - FRED_MAX_WIDTH - 10; 241 max = 10; 242 } else { 243 min = 0; 244 max = scp->xsize - FRED_MAX_WIDTH; 245 } 246 if (dxpos <= min) { 247 dxpos = min; 248 dxdir = 1; 249 } else if (dxpos >= max) { 250 dxpos = max; 251 dxdir = -1; 252 } 253 254 if (scp->ysize <= FRED_MAX_HEIGHT) { 255 min = scp->ysize - FRED_MAX_HEIGHT - 10; 256 max = 10; 257 } else { 258 min = 0; 259 max = scp->ysize - FRED_MAX_HEIGHT; 260 } 261 if (dypos <= min) { 262 dypos = min; 263 dydir = 1; 264 } else if (dypos >= max) { 265 dypos = max; 266 dydir = -1; 267 } 268 269 moved_fred = -1; 270 dxpos += dxdir; dypos += dydir; 271 272 /* clip the picture */ 273 xoff = 0; 274 xlen = FRED_MAX_WIDTH; 275 if (dxpos + xlen <= 0) 276 xlen = 0; 277 else if (dxpos < 0) 278 xoff = -dxpos; 279 if (dxpos >= scp->xsize) 280 xlen = 0; 281 else if (dxpos + xlen > scp->xsize) 282 xlen = scp->xsize - dxpos; 283 yoff = 0; 284 ylen = FRED_MAX_HEIGHT; 285 if (dypos + ylen <= 0) 286 ylen = 0; 287 else if (dypos < 0) 288 yoff = -dypos; 289 if (dypos >= scp->ysize) 290 ylen = 0; 291 else if (dypos + ylen > scp->ysize) 292 ylen = scp->ysize - dypos; 293 } 294 295 if (scp->xsize <= messagelen) { 296 min = scp->xsize - messagelen - 10; 297 max = 10; 298 } else { 299 min = 0; 300 max = scp->xsize - messagelen; 301 } 302 if (txpos <= min) { 303 txpos = min; 304 txdir = 1; 305 } else if (txpos >= max) { 306 txpos = max; 307 txdir = -1; 308 } 309 if (typos <= 0) { 310 typos = 0; 311 tydir = 1; 312 } else if (typos >= scp->ysize - 1) { 313 typos = scp->ysize - 1; 314 tydir = -1; 315 } 316 txpos += txdir; typos += tydir; 317 318 toff = 0; 319 tlen = messagelen; 320 if (txpos + tlen <= 0) 321 tlen = 0; 322 else if (txpos < 0) 323 toff = -txpos; 324 if (txpos >= scp->xsize) 325 tlen = 0; 326 else if (txpos + tlen > scp->xsize) 327 tlen = scp->xsize - txpos; 328 329 draw_fred(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen); 330 draw_string(sc, txpos, typos, toff, message, tlen); 331 } else { 332 blanked = 0; 333 } 334 return 0; 335 } 336 337 static int 338 fred_init(video_adapter_t *adp) 339 { 340 messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 + 341 strlen(osrelease); 342 message = kmalloc(messagelen + 1, M_SYSCONS, M_WAITOK); 343 ksprintf(message, "%s - %s %s", hostname, ostype, osrelease); 344 blanked = 0; 345 return 0; 346 } 347 348 static int 349 fred_term(video_adapter_t *adp) 350 { 351 kfree(message, M_SYSCONS); 352 return 0; 353 } 354 355 static scrn_saver_t fred_module = { 356 "fred_saver", fred_init, fred_term, fred_saver, NULL, 357 }; 358 359 SAVER_MODULE(fred_saver, fred_module); 360