xref: /dragonfly/sys/dev/misc/syscons/fred/fred_saver.c (revision 0ca59c34)
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
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
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
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
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
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
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
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
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