daemon_saver.c revision 111119
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: head/sys/dev/syscons/daemon/daemon_saver.c 111119 2003-02-19 05:47:46Z imp $
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
53static u_char *message;
54static int messagelen;
55static int blanked;
56
57/* Who is the author of this ASCII pic? */
58
59static u_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
82static u_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
110static u_char
111xflip_symbol(u_char symbol)
112{
113	static const u_char lchars[] = "`'(){}[]\\/<>";
114	static const u_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
124static void
125clear_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
140static void
141draw_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
191static void
192clear_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
201static void
202draw_string(sc_softc_t *sc, int xpos, int ypos, int xoff, u_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
219static int
220daemon_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, 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, 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
381static int
382daemon_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
392static int
393daemon_term(video_adapter_t *adp)
394{
395	free(message, M_DEVBUF);
396	return 0;
397}
398
399static scrn_saver_t daemon_module = {
400	"daemon_saver", daemon_init, daemon_term, daemon_saver, NULL,
401};
402
403SAVER_MODULE(daemon_saver, daemon_module);
404