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