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