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