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
xflip_symbol(u_char symbol)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
clear_fred(sc_softc_t * sc,int xpos,int ypos,int dxdir,int xoff,int yoff,int xlen,int ylen)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
draw_fred(sc_softc_t * sc,int xpos,int ypos,int dxdir,int xoff,int yoff,int xlen,int ylen)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
clear_string(sc_softc_t * sc,int xpos,int ypos,int xoff,char * s,int len)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
draw_string(sc_softc_t * sc,int xpos,int ypos,int xoff,char * s,int len)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
fred_saver(video_adapter_t * adp,int blank)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
fred_init(video_adapter_t * adp)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
fred_term(video_adapter_t * adp)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);
367