xref: /dragonfly/sys/dev/misc/syscons/fred/fred_saver.c (revision b7367ef6)
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.8 2007/08/09 02:27:51 swildner 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 #define FRED_MAX_WIDTH	31
48 #define FRED_MAX_HEIGHT	15
49 
50 static char *message;
51 static int messagelen;
52 static int blanked;
53 
54 static const char *fred_pic[] = {
55 	",--,           |           ,--,",
56 	"|   `-,       ,^,       ,-'   |",
57 	" `,    `-,   (/ \\)   ,-'    ,'",
58 	"   `-,    `-,/   \\,-'    ,-'",
59 	"      `------(   )------'",
60 	"  ,----------(   )----------,",
61 	" |        _,-(   )-,_        |",
62 	"  `-,__,-'   \\   /   `-,__,-'",
63 	"              | |",
64 	"              | |",
65 	"              | |",
66 	"              | |",
67 	"              | |",
68 	"              | |",
69 	"              `|'",
70 	NULL
71 };
72 
73 static const char *fred_attr[] = {
74 	"WWWW           R           WWWW",
75 	"W   WWW       RRR       WWW   W",
76 	" WW    WWW   GR RG   WWW    WW ",
77 	"   WWW    WWWR   RWWW    WWW",
78 	"      WWWWWWWR   RWWWWWWW",
79 	"  WWWWWWWWWWWR   RWWWWWWWWWWW",
80 	" W        WWWR   RWWW        W",
81 	"  WWWWWWWW   R   R   WWWWWWWW",
82 	"              R R",
83 	"              R R",
84 	"              R R",
85 	"              R R",
86 	"              R R",
87 	"              R R",
88 	"              RRR",
89 	NULL
90 };
91 
92 /*
93  * Reverse a graphics character, or return unaltered if no mirror;
94  * should do alphanumerics too, but I'm too lazy. <cshenton@it.hq.nasa.gov>
95  */
96 
97 static u_char
98 xflip_symbol(u_char symbol)
99 {
100 	static const u_char lchars[] = "`'(){}[]\\/<>";
101 	static const u_char rchars[] = "'`)(}{][/\\><";
102 	int pos;
103 
104 	for (pos = 0; lchars[pos] != '\0'; pos++)
105 		if (lchars[pos] == symbol)
106 			return rchars[pos];
107 
108 	return symbol;
109 }
110 
111 static void
112 clear_fred(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff,
113 	    int xlen, int ylen)
114 {
115 	int y;
116 
117 	if (xlen <= 0)
118 		return;
119 	for (y = yoff; y < ylen; y++) {
120 		sc_vtb_erase(&sc->cur_scp->scr,
121 			     (ypos + y)*sc->cur_scp->xsize + xpos + xoff,
122 			     xlen - xoff,
123 			     sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8);
124 	}
125 }
126 
127 static void
128 draw_fred(sc_softc_t *sc, int xpos, int ypos, int dxdir, int xoff, int yoff,
129 	    int xlen, int ylen)
130 {
131 	int x, y;
132 	int px;
133 	int attr;
134 
135 	for (y = yoff; y < ylen; y++) {
136 		if (dxdir < 0)
137 			px = xoff;
138 		else
139 			px = FRED_MAX_WIDTH - xlen;
140 		if (px >= strlen(fred_pic[y]))
141 			continue;
142 		for (x = xoff; (x < xlen) && (fred_pic[y][px] != '\0'); x++, px++) {
143 			switch (fred_attr[y][px]) {
144 			case 'R': attr = (FG_LIGHTRED|BG_BLACK)<<8; break;
145 			case 'G': attr = (FG_LIGHTGREEN|BG_BLACK)<<8; break;
146 			case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break;
147 			default: attr = (FG_WHITE|BG_BLACK)<<8; break;
148 			}
149 			if (dxdir < 0) {	/* Moving left */
150 				sc_vtb_putc(&sc->cur_scp->scr,
151 					    (ypos + y)*sc->cur_scp->xsize
152 						 + xpos + x,
153 					    sc->scr_map[(int)fred_pic[y][px]],
154 					    attr);
155 			} else {		/* Moving right */
156 				sc_vtb_putc(&sc->cur_scp->scr,
157 					    (ypos + y)*sc->cur_scp->xsize
158 						+ xpos + FRED_MAX_WIDTH
159 						- px - 1,
160 					    sc->scr_map[xflip_symbol(fred_pic[y][px])],
161 					    attr);
162 			}
163 		}
164 	}
165 }
166 
167 static void
168 clear_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len)
169 {
170 	if (len <= 0)
171 		return;
172 	sc_vtb_erase(&sc->cur_scp->scr,
173 		     ypos*sc->cur_scp->xsize + xpos + xoff, len - xoff,
174 		     sc->scr_map[0x20], (FG_LIGHTGREY | BG_BLACK) << 8);
175 }
176 
177 static void
178 draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, char *s, int len)
179 {
180 	int x;
181 
182 	for (x = xoff; x < len; x++) {
183 		sc_vtb_putc(&sc->cur_scp->scr,
184 			    ypos*sc->cur_scp->xsize + xpos + x,
185 			    sc->scr_map[(int)s[x]], (FG_LIGHTBLUE | BG_BLACK) << 8);
186 	}
187 }
188 
189 static int
190 fred_saver(video_adapter_t *adp, int blank)
191 {
192 	static int txpos = 10, typos = 10;
193 	static int txdir = -1, tydir = -1;
194 	static int dxpos = 0, dypos = 0;
195 	static int dxdir = 1, dydir = 1;
196 	static int moved_fred = 0;
197 	static int xoff, yoff, toff;
198 	static int xlen, ylen, tlen;
199 	sc_softc_t *sc;
200 	scr_stat *scp;
201 	int min, max;
202 
203 	sc = sc_find_softc(adp, NULL);
204 	if (sc == NULL)
205 		return EAGAIN;
206 	scp = sc->cur_scp;
207 
208 	if (blank) {
209 		if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
210 			return EAGAIN;
211 		if (blanked == 0) {
212 			/* clear the screen and set the border color */
213 			sc_vtb_clear(&scp->scr, sc->scr_map[0x20],
214 				     (FG_LIGHTGREY | BG_BLACK) << 8);
215 			(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
216 			sc_set_border(scp, 0);
217 			xlen = ylen = tlen = 0;
218 		}
219 		if (blanked++ < 2)
220 			return 0;
221 		blanked = 1;
222 
223  		clear_fred(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
224 		clear_string(sc, txpos, typos, toff, message, tlen);
225 
226 		if (++moved_fred) {
227 			/*
228 			 * Fred's picture may be off the screen, if
229 			 * screen size is chagened while the screen
230 			 * saver is inactive. Make sure the origin of
231 			 * the picture is between min and max.
232 			 */
233 			if (scp->xsize <= FRED_MAX_WIDTH) {
234 				/*
235 				 * If the screen width is too narrow, we
236 				 * allow part of the picture go off
237 				 * the screen so that Fred won't
238 				 * flip too often.
239 				 */
240 				min = scp->xsize - FRED_MAX_WIDTH - 10;
241 				max = 10;
242 			} else {
243 				min = 0;
244 				max = scp->xsize - FRED_MAX_WIDTH;
245 			}
246 			if (dxpos <= min) {
247 				dxpos = min;
248 				dxdir = 1;
249 			} else if (dxpos >= max) {
250 				dxpos = max;
251 				dxdir = -1;
252 			}
253 
254 			if (scp->ysize <= FRED_MAX_HEIGHT) {
255 				min = scp->ysize - FRED_MAX_HEIGHT - 10;
256 				max = 10;
257 			} else {
258 				min = 0;
259 				max = scp->ysize - FRED_MAX_HEIGHT;
260 			}
261 			if (dypos <= min) {
262 				dypos = min;
263 				dydir = 1;
264 			} else if (dypos >= max) {
265 				dypos = max;
266 				dydir = -1;
267 			}
268 
269 			moved_fred = -1;
270 			dxpos += dxdir; dypos += dydir;
271 
272 			/* clip the picture */
273 			xoff = 0;
274 			xlen = FRED_MAX_WIDTH;
275 			if (dxpos + xlen <= 0)
276 				xlen = 0;
277 			else if (dxpos < 0)
278 				xoff = -dxpos;
279 			if (dxpos >= scp->xsize)
280 				xlen = 0;
281 			else if (dxpos + xlen > scp->xsize)
282 				xlen = scp->xsize - dxpos;
283 			yoff = 0;
284 			ylen = FRED_MAX_HEIGHT;
285 			if (dypos + ylen <= 0)
286 				ylen = 0;
287 			else if (dypos < 0)
288 				yoff = -dypos;
289 			if (dypos >= scp->ysize)
290 				ylen = 0;
291 			else if (dypos + ylen > scp->ysize)
292 				ylen = scp->ysize - dypos;
293 		}
294 
295 		if (scp->xsize <= messagelen) {
296 			min = scp->xsize - messagelen - 10;
297 			max = 10;
298 		} else {
299 			min = 0;
300 			max = scp->xsize - messagelen;
301 		}
302 		if (txpos <= min) {
303 			txpos = min;
304 			txdir = 1;
305 		} else if (txpos >= max) {
306 			txpos = max;
307 			txdir = -1;
308 		}
309 		if (typos <= 0) {
310 			typos = 0;
311 			tydir = 1;
312 		} else if (typos >= scp->ysize - 1) {
313 			typos = scp->ysize - 1;
314 			tydir = -1;
315 		}
316 		txpos += txdir; typos += tydir;
317 
318 		toff = 0;
319 		tlen = messagelen;
320 		if (txpos + tlen <= 0)
321 			tlen = 0;
322 		else if (txpos < 0)
323 			toff = -txpos;
324 		if (txpos >= scp->xsize)
325 			tlen = 0;
326 		else if (txpos + tlen > scp->xsize)
327 			tlen = scp->xsize - txpos;
328 
329  		draw_fred(sc, dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
330 		draw_string(sc, txpos, typos, toff, message, tlen);
331 	} else {
332 		blanked = 0;
333 	}
334 	return 0;
335 }
336 
337 static int
338 fred_init(video_adapter_t *adp)
339 {
340 	messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 +
341 	    strlen(osrelease);
342 	message = kmalloc(messagelen + 1, M_SYSCONS, M_WAITOK);
343 	ksprintf(message, "%s - %s %s", hostname, ostype, osrelease);
344 	blanked = 0;
345 	return 0;
346 }
347 
348 static int
349 fred_term(video_adapter_t *adp)
350 {
351 	kfree(message, M_SYSCONS);
352 	return 0;
353 }
354 
355 static scrn_saver_t fred_module = {
356 	"fred_saver", fred_init, fred_term, fred_saver, NULL,
357 };
358 
359 SAVER_MODULE(fred_saver, fred_module);
360