daemon_saver.c revision 56043
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 56043 2000-01-15 15:25:43Z yokota $
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
49static char *message;
50static int messagelen;
51static int blanked;
52
53/* Who is the author of this ASCII pic? */
54
55static 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
78static 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
106static char
107xflip_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
120static void
121clear_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
136static void
137draw_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
187static void
188clear_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
197static void
198draw_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
209static int
210daemon_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
371static int
372daemon_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
382static int
383daemon_term(video_adapter_t *adp)
384{
385	free(message, M_DEVBUF);
386	return 0;
387}
388
389static scrn_saver_t daemon_module = {
390	"daemon_saver", daemon_init, daemon_term, daemon_saver, NULL,
391};
392
393SAVER_MODULE(daemon_saver, daemon_module);
394