un-tokenize savers
[dragonfly.git] / sys / dev / misc / syscons / fred / fred_saver.c
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);