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