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