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