1 /*
2  *   Creation Date: <2002/10/23 20:26:40 samuel>
3  *   Time-stamp: <2004/01/07 19:39:15 samuel>
4  *
5  *     <video_common.c>
6  *
7  *     Shared video routines
8  *
9  *   Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   as published by the Free Software Foundation
14  *
15  */
16 
17 #include "config.h"
18 #include "libc/vsprintf.h"
19 #include "libopenbios/bindings.h"
20 #include "libopenbios/fontdata.h"
21 #include "libopenbios/ofmem.h"
22 #include "libopenbios/video.h"
23 #include "packages/video.h"
24 #include "drivers/vga.h"
25 #define NO_QEMU_PROTOS
26 #include "arch/common/fw_cfg.h"
27 
28 struct video_info video;
29 
30 unsigned long
video_get_color(int col_ind)31 video_get_color( int col_ind )
32 {
33 	unsigned long col;
34 	if( !VIDEO_DICT_VALUE(video.ih) || col_ind < 0 || col_ind > 255 )
35 		return 0;
36 	if( VIDEO_DICT_VALUE(video.depth) == 8 )
37 		return col_ind;
38 	col = video.pal[col_ind];
39 	if( VIDEO_DICT_VALUE(video.depth) == 24 || VIDEO_DICT_VALUE(video.depth) == 32 )
40 		return col;
41 	if( VIDEO_DICT_VALUE(video.depth) == 15 )
42 		return ((col>>9) & 0x7c00) | ((col>>6) & 0x03e0) | ((col>>3) & 0x1f);
43 	return 0;
44 }
45 
46 /* ( fbaddr maskaddr width height fgcolor bgcolor -- ) */
47 
48 void
video_mask_blit(void)49 video_mask_blit(void)
50 {
51 	ucell bgcolor = POP();
52 	ucell fgcolor = POP();
53 	ucell height = POP();
54 	ucell width = POP();
55 	unsigned char *mask = (unsigned char *)POP();
56 	unsigned char *fbaddr = (unsigned char *)POP();
57 
58 	ucell color;
59 	unsigned char *dst, *rowdst;
60 	int x, y, m, b, d, depthbytes;
61 
62 	fgcolor = video_get_color(fgcolor);
63 	bgcolor = video_get_color(bgcolor);
64 	d = VIDEO_DICT_VALUE(video.depth);
65 	depthbytes = (d + 1) >> 3;
66 
67 	dst = fbaddr;
68 	for( y = 0; y < height; y++) {
69 		rowdst = dst;
70 		for( x = 0; x < (width + 1) >> 3; x++ ) {
71 			for (b = 0; b < 8; b++) {
72 				m = (1 << (7 - b));
73 
74 				if (*mask & m) {
75 					color = fgcolor;
76 				} else {
77 					color = bgcolor;
78 				}
79 
80 				if( d >= 24 )
81 					*((uint32_t*)dst) = color;
82 				else if( d >= 15 )
83 					*((uint16_t*)dst) = color;
84 				else
85 					*dst = color;
86 
87 				dst += depthbytes;
88 			}
89 			mask++;
90 		}
91 		dst = rowdst;
92 		dst += VIDEO_DICT_VALUE(video.rb);
93 	}
94 }
95 
96 /* ( x y w h fgcolor bgcolor -- ) */
97 
98 void
video_invert_rect(void)99 video_invert_rect( void )
100 {
101 	ucell bgcolor = POP();
102 	ucell fgcolor = POP();
103 	int h = POP();
104 	int w = POP();
105 	int y = POP();
106 	int x = POP();
107 	char *pp;
108 
109 	bgcolor = video_get_color(bgcolor);
110 	fgcolor = video_get_color(fgcolor);
111 
112 	if (!VIDEO_DICT_VALUE(video.ih) || x < 0 || y < 0 || w <= 0 || h <= 0 ||
113 		x + w > VIDEO_DICT_VALUE(video.w) || y + h > VIDEO_DICT_VALUE(video.h))
114 		return;
115 
116 	pp = (char*)VIDEO_DICT_VALUE(video.mvirt) + VIDEO_DICT_VALUE(video.rb) * y;
117 	for( ; h--; pp += *(video.rb) ) {
118 		int ww = w;
119 		if( VIDEO_DICT_VALUE(video.depth) == 24 || VIDEO_DICT_VALUE(video.depth) == 32 ) {
120 			uint32_t *p = (uint32_t*)pp + x;
121 			while( ww-- ) {
122 				if (*p == fgcolor) {
123 					*p++ = bgcolor;
124 				} else if (*p == bgcolor) {
125 					*p++ = fgcolor;
126 				}
127 			}
128 		} else if( VIDEO_DICT_VALUE(video.depth) == 16 || VIDEO_DICT_VALUE(video.depth) == 15 ) {
129 			uint16_t *p = (uint16_t*)pp + x;
130 			while( ww-- ) {
131 				if (*p == (uint16_t)fgcolor) {
132 					*p++ = bgcolor;
133 				} else if (*p == (uint16_t)bgcolor) {
134 					*p++ = fgcolor;
135 				}
136 			}
137 		} else {
138 			char *p = (char *)(pp + x);
139 
140 			while( ww-- ) {
141 				if (*p == (char)fgcolor) {
142 					*p++ = bgcolor;
143 				} else if (*p == (char)bgcolor) {
144 					*p++ = fgcolor;
145 				}
146 			}
147 		}
148 	}
149 }
150 
151 /* ( color_ind x y width height -- ) (?) */
152 void
video_fill_rect(void)153 video_fill_rect(void)
154 {
155 	int h = POP();
156 	int w = POP();
157 	int y = POP();
158 	int x = POP();
159 	int col_ind = POP();
160 
161 	char *pp;
162 	unsigned long col = video_get_color(col_ind);
163 
164         if (!VIDEO_DICT_VALUE(video.ih) || x < 0 || y < 0 || w <= 0 || h <= 0 ||
165             x + w > VIDEO_DICT_VALUE(video.w) || y + h > VIDEO_DICT_VALUE(video.h))
166 		return;
167 
168 	pp = (char*)VIDEO_DICT_VALUE(video.mvirt) + VIDEO_DICT_VALUE(video.rb) * y;
169 	for( ; h--; pp += VIDEO_DICT_VALUE(video.rb) ) {
170 		int ww = w;
171 		if( VIDEO_DICT_VALUE(video.depth) == 24 || VIDEO_DICT_VALUE(video.depth) == 32 ) {
172 			uint32_t *p = (uint32_t*)pp + x;
173 			while( ww-- )
174 				*p++ = col;
175 		} else if( VIDEO_DICT_VALUE(video.depth) == 16 || VIDEO_DICT_VALUE(video.depth) == 15 ) {
176 			uint16_t *p = (uint16_t*)pp + x;
177 			while( ww-- )
178 				*p++ = col;
179 		} else {
180                         char *p = (char *)(pp + x);
181 
182 			while( ww-- )
183 				*p++ = col;
184 		}
185 	}
186 }
187 
setup_video()188 void setup_video()
189 {
190 	/* Make everything inside the video_info structure point to the
191 	   values in the Forth dictionary. Hence everything is always in
192 	   sync. */
193 	phandle_t options;
194 	char buf[10];
195 
196 	feval("['] display-ih cell+");
197 	video.ih = cell2pointer(POP());
198 
199 	feval("['] frame-buffer-adr cell+");
200 	video.mvirt = cell2pointer(POP());
201 	feval("['] openbios-video-width cell+");
202 	video.w = cell2pointer(POP());
203 	feval("['] openbios-video-height cell+");
204 	video.h = cell2pointer(POP());
205 	feval("['] depth-bits cell+");
206 	video.depth = cell2pointer(POP());
207 	feval("['] line-bytes cell+");
208 	video.rb = cell2pointer(POP());
209 	feval("['] color-palette cell+");
210 	video.pal = cell2pointer(POP());
211 
212 	/* Set global variables ready for fb8-install */
213 	PUSH( pointer2cell(video_mask_blit) );
214 	fword("is-noname-cfunc");
215 	feval("to fb8-blitmask");
216 	PUSH( pointer2cell(video_fill_rect) );
217 	fword("is-noname-cfunc");
218 	feval("to fb8-fillrect");
219 	PUSH( pointer2cell(video_invert_rect) );
220 	fword("is-noname-cfunc");
221 	feval("to fb8-invertrect");
222 
223 	/* Static information */
224 	PUSH((ucell)fontdata);
225 	feval("to (romfont)");
226 	PUSH(FONT_HEIGHT);
227 	feval("to (romfont-height)");
228 	PUSH(FONT_WIDTH);
229 	feval("to (romfont-width)");
230 
231 	/* Initialise the structure */
232 	VIDEO_DICT_VALUE(video.w) = VGA_DEFAULT_WIDTH;
233 	VIDEO_DICT_VALUE(video.h) = VGA_DEFAULT_HEIGHT;
234 	VIDEO_DICT_VALUE(video.depth) = VGA_DEFAULT_DEPTH;
235 	VIDEO_DICT_VALUE(video.rb) = VGA_DEFAULT_LINEBYTES;
236 
237 #if defined(CONFIG_QEMU) && (defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64))
238 	/* If running from QEMU, grab the parameters from the firmware interface */
239 	int w, h, d;
240 
241 	w = fw_cfg_read_i16(FW_CFG_ARCH_WIDTH);
242         h = fw_cfg_read_i16(FW_CFG_ARCH_HEIGHT);
243         d = fw_cfg_read_i16(FW_CFG_ARCH_DEPTH);
244 	if (w && h && d) {
245 		VIDEO_DICT_VALUE(video.w) = w;
246 		VIDEO_DICT_VALUE(video.h) = h;
247 		VIDEO_DICT_VALUE(video.depth) = d;
248 		VIDEO_DICT_VALUE(video.rb) = (w * ((d + 7) / 8));
249 	}
250 #endif
251 
252 	/* Setup screen-#rows/screen-#columns */
253 	options = find_dev("/options");
254 	snprintf(buf, sizeof(buf), FMT_ucell, VIDEO_DICT_VALUE(video.w) / FONT_WIDTH);
255 	set_property(options, "screen-#columns", buf, strlen(buf) + 1);
256 	snprintf(buf, sizeof(buf), FMT_ucell, VIDEO_DICT_VALUE(video.h) / FONT_HEIGHT);
257 	set_property(options, "screen-#rows", buf, strlen(buf) + 1);
258 }
259