1 /*
2 * linux/drivers/video/ilbm.c -- Low level frame buffer operations for
3 * interleaved bitplanes � la Amiga
4 *
5 * Created 5 Apr 1997 by Geert Uytterhoeven
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
10 */
11
12 #include <linux/module.h>
13 #include <linux/tty.h>
14 #include <linux/console.h>
15 #include <linux/string.h>
16 #include <linux/fb.h>
17
18 #include <video/fbcon.h>
19 #include <video/fbcon-ilbm.h>
20
21
22 /*
23 * Interleaved bitplanes � la Amiga
24 *
25 * This code heavily relies on the fact that
26 *
27 * next_line == interleave == next_plane*bits_per_pixel
28 *
29 * But maybe it can be merged with the code for normal bitplanes without
30 * much performance loss?
31 */
32
fbcon_ilbm_setup(struct display * p)33 void fbcon_ilbm_setup(struct display *p)
34 {
35 if (p->line_length) {
36 p->next_line = p->line_length*p->var.bits_per_pixel;
37 p->next_plane = p->line_length;
38 } else {
39 p->next_line = p->type_aux;
40 p->next_plane = p->type_aux/p->var.bits_per_pixel;
41 }
42 }
43
fbcon_ilbm_bmove(struct display * p,int sy,int sx,int dy,int dx,int height,int width)44 void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
45 int height, int width)
46 {
47 if (sx == 0 && dx == 0 && width == p->next_plane)
48 fb_memmove(p->screen_base+dy*fontheight(p)*p->next_line,
49 p->screen_base+sy*fontheight(p)*p->next_line,
50 height*fontheight(p)*p->next_line);
51 else {
52 u8 *src, *dest;
53 u_int i;
54
55 if (dy <= sy) {
56 src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
57 dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
58 for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
59 fb_memmove(dest, src, width);
60 src += p->next_plane;
61 dest += p->next_plane;
62 }
63 } else {
64 src = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx;
65 dest = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx;
66 for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
67 src -= p->next_plane;
68 dest -= p->next_plane;
69 fb_memmove(dest, src, width);
70 }
71 }
72 }
73 }
74
fbcon_ilbm_clear(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)75 void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, int sx,
76 int height, int width)
77 {
78 u8 *dest;
79 u_int i, rows;
80 int bg, bg0;
81
82 dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
83
84 bg0 = attr_bgcol_ec(p,conp);
85 for (rows = height*fontheight(p); rows--;) {
86 bg = bg0;
87 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
88 if (bg & 1)
89 fb_memset255(dest, width);
90 else
91 fb_memclear(dest, width);
92 bg >>= 1;
93 }
94 }
95 }
96
fbcon_ilbm_putc(struct vc_data * conp,struct display * p,int c,int yy,int xx)97 void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, int yy,
98 int xx)
99 {
100 u8 *dest, *cdat;
101 u_int rows, i;
102 u8 d;
103 int fg0, bg0, fg, bg;
104
105 dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
106 cdat = p->fontdata+(c&p->charmask)*fontheight(p);
107 fg0 = attr_fgcol(p,c);
108 bg0 = attr_bgcol(p,c);
109
110 for (rows = fontheight(p); rows--;) {
111 d = *cdat++;
112 fg = fg0;
113 bg = bg0;
114 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
115 if (bg & 1){
116 if (fg & 1)
117 *dest = 0xff;
118 else
119 *dest = ~d;
120 }else{
121 if (fg & 1)
122 *dest = d;
123 else
124 *dest = 0x00;
125 }
126 bg >>= 1;
127 fg >>= 1;
128 }
129 }
130 }
131
132 /*
133 * I've split the console character loop in two parts:
134 *
135 * - slow version: this blits one character at a time
136 *
137 * - fast version: this blits 4 characters at a time at a longword
138 * aligned address, to reduce the number of expensive
139 * Chip RAM accesses.
140 *
141 * Experiments on my A4000/040 revealed that this makes a console switch
142 * on a 640x400 screen with 256 colors about 3 times faster.
143 *
144 * -- Geert
145 */
146
fbcon_ilbm_putcs(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)147 void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p,
148 const unsigned short *s, int count, int yy, int xx)
149 {
150 u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
151 u_int rows, i;
152 u16 c1, c2, c3, c4;
153 u32 d;
154 int fg0, bg0, fg, bg;
155
156 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
157 c1 = scr_readw(s);
158 fg0 = attr_fgcol(p, c1);
159 bg0 = attr_bgcol(p, c1);
160
161 while (count--)
162 if (xx&3 || count < 3) { /* Slow version */
163 c1 = scr_readw(s++) & p->charmask;
164 dest = dest0++;
165 xx++;
166
167 cdat1 = p->fontdata+c1*fontheight(p);
168 for (rows = fontheight(p); rows--;) {
169 d = *cdat1++;
170 fg = fg0;
171 bg = bg0;
172 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
173 if (bg & 1){
174 if (fg & 1)
175 *dest = 0xff;
176 else
177 *dest = ~d;
178 }else{
179 if (fg & 1)
180 *dest = d;
181 else
182 *dest = 0x00;
183 }
184 bg >>= 1;
185 fg >>= 1;
186 }
187 }
188 } else { /* Fast version */
189 c1 = scr_readw(&s[0]) & p->charmask;
190 c2 = scr_readw(&s[1]) & p->charmask;
191 c3 = scr_readw(&s[2]) & p->charmask;
192 c4 = scr_readw(&s[3]) & p->charmask;
193
194 dest = dest0;
195 cdat1 = p->fontdata+c1*fontheight(p);
196 cdat2 = p->fontdata+c2*fontheight(p);
197 cdat3 = p->fontdata+c3*fontheight(p);
198 cdat4 = p->fontdata+c4*fontheight(p);
199 for (rows = fontheight(p); rows--;) {
200 #if defined(__BIG_ENDIAN)
201 d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
202 #elif defined(__LITTLE_ENDIAN)
203 d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<24;
204 #else
205 #error FIXME: No endianness??
206 #endif
207 fg = fg0;
208 bg = bg0;
209 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
210 if (bg & 1){
211 if (fg & 1)
212 *(u32 *)dest = 0xffffffff;
213 else
214 *(u32 *)dest = ~d;
215 }else{
216 if (fg & 1)
217 *(u32 *)dest = d;
218 else
219 *(u32 *)dest = 0x00000000;
220 }
221 bg >>= 1;
222 fg >>= 1;
223 }
224 }
225 s += 4;
226 dest0 += 4;
227 xx += 4;
228 count -= 3;
229 }
230 }
231
fbcon_ilbm_revc(struct display * p,int xx,int yy)232 void fbcon_ilbm_revc(struct display *p, int xx, int yy)
233 {
234 u8 *dest, *dest0;
235 u_int rows, i;
236 int mask;
237
238 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
239 mask = p->fgcol ^ p->bgcol;
240
241 /*
242 * This should really obey the individual character's
243 * background and foreground colors instead of simply
244 * inverting.
245 */
246
247 for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
248 if (mask & 1) {
249 dest = dest0;
250 for (rows = fontheight(p); rows--; dest += p->next_line)
251 *dest = ~*dest;
252 }
253 mask >>= 1;
254 }
255 }
256
257
258 /*
259 * `switch' for the low level operations
260 */
261
262 struct display_switch fbcon_ilbm = {
263 setup: fbcon_ilbm_setup,
264 bmove: fbcon_ilbm_bmove,
265 clear: fbcon_ilbm_clear,
266 putc: fbcon_ilbm_putc,
267 putcs: fbcon_ilbm_putcs,
268 revc: fbcon_ilbm_revc,
269 fontwidthmask: FONTWIDTH(8)
270 };
271
272
273 #ifdef MODULE
274 MODULE_LICENSE("GPL");
275
init_module(void)276 int init_module(void)
277 {
278 return 0;
279 }
280
cleanup_module(void)281 void cleanup_module(void)
282 {}
283 #endif /* MODULE */
284
285
286 /*
287 * Visible symbols for modules
288 */
289
290 EXPORT_SYMBOL(fbcon_ilbm);
291 EXPORT_SYMBOL(fbcon_ilbm_setup);
292 EXPORT_SYMBOL(fbcon_ilbm_bmove);
293 EXPORT_SYMBOL(fbcon_ilbm_clear);
294 EXPORT_SYMBOL(fbcon_ilbm_putc);
295 EXPORT_SYMBOL(fbcon_ilbm_putcs);
296 EXPORT_SYMBOL(fbcon_ilbm_revc);
297