xref: /freebsd/sys/dev/syscons/daemon/daemon_saver.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 			vidd_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);
383