xref: /freebsd/sys/dev/syscons/daemon/daemon_saver.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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  *	$Id: daemon_saver.c,v 1.8 1998/01/16 17:58:43 bde Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/exec.h>
34 #include <sys/sysent.h>
35 #include <sys/lkm.h>
36 #include <sys/malloc.h>
37 #include <sys/kernel.h>
38 #include <sys/sysctl.h>
39 
40 #include <machine/md_var.h>
41 #include <machine/pc/display.h>
42 
43 #include <saver.h>
44 
45 #define CONSOLE_VECT(x, y) \
46 	((u_short*)(Crtat + (y)*cur_console->xsize + (x)))
47 
48 #define DAEMON_MAX_WIDTH	32
49 #define DAEMON_MAX_HEIGHT	19
50 
51 MOD_MISC(daemon_saver);
52 
53 static char *message;
54 static int messagelen;
55 
56 /* Who is the author of this ASCII pic? */
57 
58 static 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 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 char
110 xflip_symbol(char symbol)
111 {
112 	static const char lchars[] = "`'(){}[]\\/<>";
113 	static const 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(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 		fillw(((FG_LIGHTGREY|BG_BLACK) << 8) | scr_map[0x20],
133 		      CONSOLE_VECT(xpos + xoff, ypos + y), xlen - xoff);
134 }
135 
136 static void
137 draw_daemon(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 			case 'R': attr = (FG_LIGHTRED|BG_BLACK)<<8; break;
154 			case 'Y': attr = (FG_YELLOW|BG_BLACK)<<8; break;
155 			case 'B': attr = (FG_LIGHTBLUE|BG_BLACK)<<8; break;
156 			case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break;
157 			case 'C': attr = (FG_CYAN|BG_BLACK)<<8; break;
158 			default: attr = (FG_WHITE|BG_BLACK)<<8; break;
159 			}
160 			if (dxdir < 0) {	/* Moving left */
161 				*CONSOLE_VECT(xpos + x, ypos + y) =
162 					scr_map[daemon_pic[y][px]]|attr;
163 			} else {		/* Moving right */
164 				*CONSOLE_VECT(xpos + DAEMON_MAX_WIDTH - px - 1, ypos + y) =
165 					scr_map[xflip_symbol(daemon_pic[y][px])]|attr;
166 			}
167 		}
168 	}
169 }
170 
171 static void
172 clear_string(int xpos, int ypos, int xoff, char *s, int len)
173 {
174 	if (len <= 0)
175 		return;
176 	fillw(((FG_LIGHTGREY|BG_BLACK) << 8) | scr_map[0x20],
177 	      CONSOLE_VECT(xpos + xoff, ypos), len - xoff);
178 }
179 
180 static void
181 draw_string(int xpos, int ypos, int xoff, char *s, int len)
182 {
183 	int x;
184 
185 	for (x = xoff; x < len; x++)
186 		*CONSOLE_VECT(xpos + x, ypos) =
187 			scr_map[s[x]]|(FG_LIGHTGREEN|BG_BLACK)<<8;
188 }
189 
190 static void
191 daemon_saver(int blank)
192 {
193 	static int txpos = 10, typos = 10;
194 	static int txdir = -1, tydir = -1;
195 	static int dxpos = 0, dypos = 0;
196 	static int dxdir = 1, dydir = 1;
197 	static int moved_daemon = 0;
198 	static int xoff, yoff, toff;
199 	static int xlen, ylen, tlen;
200 	scr_stat *scp = cur_console;
201 	int min, max;
202 
203 	if (blank) {
204 		if (scrn_blanked == 0) {
205 			/* clear the screen and set the border color */
206 			fillw(((FG_LIGHTGREY|BG_BLACK) << 8) | scr_map[0x20],
207 			      Crtat, scp->xsize * scp->ysize);
208 			set_border(0);
209 			xlen = ylen = tlen = 0;
210 		}
211 		if (scrn_blanked++ < 2)
212 			return;
213 		scrn_blanked = 1;
214 
215  		clear_daemon(dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
216 		clear_string(txpos, typos, toff, (char *)message, tlen);
217 
218 		if (++moved_daemon) {
219 			/*
220 			 * The daemon picture may be off the screen, if
221 			 * screen size is chagened while the screen
222 			 * saver is inactive. Make sure the origin of
223 			 * the picture is between min and max.
224 			 */
225 			if (scp->xsize <= DAEMON_MAX_WIDTH) {
226 				/*
227 				 * If the screen width is too narrow, we
228 				 * allow part of the picture go off
229 				 * the screen so that the daemon won't
230 				 * flip too often.
231 				 */
232 				min = scp->xsize - DAEMON_MAX_WIDTH - 10;
233 				max = 10;
234 			} else {
235 				min = 0;
236 				max = scp->xsize - DAEMON_MAX_WIDTH;
237 			}
238 			if (dxpos <= min) {
239 				dxpos = min;
240 				dxdir = 1;
241 			} else if (dxpos >= max) {
242 				dxpos = max;
243 				dxdir = -1;
244 			}
245 
246 			if (scp->ysize <= DAEMON_MAX_HEIGHT) {
247 				min = scp->ysize - DAEMON_MAX_HEIGHT - 10;
248 				max = 10;
249 			} else {
250 				min = 0;
251 				max = scp->ysize - DAEMON_MAX_HEIGHT;
252 			}
253 			if (dypos <= min) {
254 				dypos = min;
255 				dydir = 1;
256 			} else if (dypos >= max) {
257 				dypos = max;
258 				dydir = -1;
259 			}
260 
261 			moved_daemon = -1;
262 			dxpos += dxdir; dypos += dydir;
263 
264 			/* clip the picture */
265 			xoff = 0;
266 			xlen = DAEMON_MAX_WIDTH;
267 			if (dxpos + xlen <= 0)
268 				xlen = 0;
269 			else if (dxpos < 0)
270 				xoff = -dxpos;
271 			if (dxpos >= scp->xsize)
272 				xlen = 0;
273 			else if (dxpos + xlen > scp->xsize)
274 				xlen = scp->xsize - dxpos;
275 			yoff = 0;
276 			ylen = DAEMON_MAX_HEIGHT;
277 			if (dypos + ylen <= 0)
278 				ylen = 0;
279 			else if (dypos < 0)
280 				yoff = -dypos;
281 			if (dypos >= scp->ysize)
282 				ylen = 0;
283 			else if (dypos + ylen > scp->ysize)
284 				ylen = scp->ysize - dypos;
285 		}
286 
287 		if (scp->xsize <= messagelen) {
288 			min = scp->xsize - messagelen - 10;
289 			max = 10;
290 		} else {
291 			min = 0;
292 			max = scp->xsize - messagelen;
293 		}
294 		if (txpos <= min) {
295 			txpos = min;
296 			txdir = 1;
297 		} else if (txpos >= max) {
298 			txpos = max;
299 			txdir = -1;
300 		}
301 		if (typos <= 0) {
302 			typos = 0;
303 			tydir = 1;
304 		} else if (typos >= scp->ysize - 1) {
305 			typos = scp->ysize - 1;
306 			tydir = -1;
307 		}
308 		txpos += txdir; typos += tydir;
309 
310 		toff = 0;
311 		tlen = messagelen;
312 		if (txpos + tlen <= 0)
313 			tlen = 0;
314 		else if (txpos < 0)
315 			toff = -txpos;
316 		if (txpos >= scp->xsize)
317 			tlen = 0;
318 		else if (txpos + tlen > scp->xsize)
319 			tlen = scp->xsize - txpos;
320 
321  		draw_daemon(dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
322 		draw_string(txpos, typos, toff, (char *)message, tlen);
323 	} else {
324 		if (scrn_blanked > 0) {
325 			set_border(scp->border);
326 			scrn_blanked = 0;
327 		}
328 	}
329 }
330 
331 static int
332 daemon_saver_load(struct lkm_table *lkmtp, int cmd)
333 {
334 	int err;
335 
336 	if (cur_console->mode >= M_VESA_BASE)
337 		return ENODEV;
338 
339 	messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 +
340 	    strlen(osrelease);
341 	message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK);
342 	sprintf(message, "%s - %s %s", hostname, ostype, osrelease);
343 
344 	err = add_scrn_saver(daemon_saver);
345 	if (err != 0)
346 		free(message, M_DEVBUF);
347 	return err;
348 }
349 
350 static int
351 daemon_saver_unload(struct lkm_table *lkmtp, int cmd)
352 {
353 	int err;
354 
355 	err = remove_scrn_saver(daemon_saver);
356 	if (err == 0)
357 		free(message, M_DEVBUF);
358 	return err;
359 }
360 
361 int
362 daemon_saver_mod(struct lkm_table *lkmtp, int cmd, int ver)
363 {
364 	MOD_DISPATCH(daemon_saver, lkmtp, cmd, ver,
365 		daemon_saver_load, daemon_saver_unload, lkm_nullcmd);
366 }
367