File: /usr/src/linux/drivers/video/fbcon-ilbm.c

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     
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     
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     
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     
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     
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         fg0 = attr_fgcol(p,scr_readw(s));
158         bg0 = attr_bgcol(p,scr_readw(s));
159     
160         while (count--)
161     	if (xx&3 || count < 3) {	/* Slow version */
162     	    c1 = scr_readw(s++) & p->charmask;
163     	    dest = dest0++;
164     	    xx++;
165     
166     	    cdat1 = p->fontdata+c1*fontheight(p);
167     	    for (rows = fontheight(p); rows--;) {
168     		d = *cdat1++;
169     		fg = fg0;
170     		bg = bg0;
171     		for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
172     		    if (bg & 1){
173     			if (fg & 1)
174     			    *dest = 0xff;
175     			else
176     			    *dest = ~d;
177     		    }else{
178     			if (fg & 1)
179     			    *dest = d;
180     			else
181     			    *dest = 0x00;
182     		    }
183     		    bg >>= 1;
184     		    fg >>= 1;
185     		}
186     	    }
187     	} else {		/* Fast version */
188     	    c1 = scr_readw(&s[0]) & p->charmask;
189     	    c2 = scr_readw(&s[1]) & p->charmask;
190     	    c3 = scr_readw(&s[2]) & p->charmask;
191     	    c4 = scr_readw(&s[3]) & p->charmask;
192     
193     	    dest = dest0;
194     	    cdat1 = p->fontdata+c1*fontheight(p);
195     	    cdat2 = p->fontdata+c2*fontheight(p);
196     	    cdat3 = p->fontdata+c3*fontheight(p);
197     	    cdat4 = p->fontdata+c4*fontheight(p);
198     	    for (rows = fontheight(p); rows--;) {
199     #if defined(__BIG_ENDIAN)
200     		d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
201     #elif defined(__LITTLE_ENDIAN)
202     		d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<24;
203     #else
204     #error FIXME: No endianness??
205     #endif
206     		fg = fg0;
207     		bg = bg0;
208     		for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
209     		    if (bg & 1){
210     			if (fg & 1)
211     			    *(u32 *)dest = 0xffffffff;
212     			else
213     			    *(u32 *)dest = ~d;
214     		    }else{
215     			if (fg & 1)
216     			    *(u32 *)dest = d;
217     			else
218     			    *(u32 *)dest = 0x00000000;
219     		    }
220     		    bg >>= 1;
221     		    fg >>= 1;
222     		}
223     	    }
224     	    s += 4;
225     	    dest0 += 4;
226     	    xx += 4;
227     	    count -= 3;
228     	}
229     }
230     
231     void fbcon_ilbm_revc(struct display *p, int xx, int yy)
232     {
233         u8 *dest, *dest0;
234         u_int rows, i;
235         int mask;
236     
237         dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
238         mask = p->fgcol ^ p->bgcol;
239     
240         /*
241          *  This should really obey the individual character's
242          *  background and foreground colors instead of simply
243          *  inverting.
244          */
245     
246         for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
247     	if (mask & 1) {
248     	    dest = dest0;
249     	    for (rows = fontheight(p); rows--; dest += p->next_line)
250     		*dest = ~*dest;
251     	}
252     	mask >>= 1;
253         }
254     }
255     
256     
257         /*
258          *  `switch' for the low level operations
259          */
260     
261     struct display_switch fbcon_ilbm = {
262         setup:		fbcon_ilbm_setup,
263         bmove:		fbcon_ilbm_bmove,
264         clear:		fbcon_ilbm_clear,
265         putc:		fbcon_ilbm_putc,
266         putcs:		fbcon_ilbm_putcs,
267         revc:		fbcon_ilbm_revc,
268         fontwidthmask:	FONTWIDTH(8)
269     };
270     
271     
272     #ifdef MODULE
273     MODULE_LICENSE("GPL");
274     
275     int init_module(void)
276     {
277         return 0;
278     }
279     
280     void cleanup_module(void)
281     {}
282     #endif /* MODULE */
283     
284     
285         /*
286          *  Visible symbols for modules
287          */
288     
289     EXPORT_SYMBOL(fbcon_ilbm);
290     EXPORT_SYMBOL(fbcon_ilbm_setup);
291     EXPORT_SYMBOL(fbcon_ilbm_bmove);
292     EXPORT_SYMBOL(fbcon_ilbm_clear);
293     EXPORT_SYMBOL(fbcon_ilbm_putc);
294     EXPORT_SYMBOL(fbcon_ilbm_putcs);
295     EXPORT_SYMBOL(fbcon_ilbm_revc);
296