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