8e2e6f947512649e722f7ad3a8536bce9ddeedb8
[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.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);