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