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

1     /*
2      *  linux/drivers/video/afb.c -- Low level frame buffer operations for
3      *				 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-afb.h>
20     
21     
22         /*
23          *  Bitplanes à la Amiga
24          */
25     
26     static u8 expand_table[1024] = {
27         /*  bg = fg = 0 */
28         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60         /* bg = 0, fg = 1 */
61         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
62         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
63         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
64         0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
65         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
66         0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
67         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
68         0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
69         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
70         0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
71         0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
72         0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
73         0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
74         0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
75         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
76         0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
77         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
78         0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
79         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
80         0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
81         0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
82         0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
83         0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
84         0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
85         0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
86         0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
87         0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
88         0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
89         0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
90         0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
91         0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
92         0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
93         /* bg = 1, fg = 0 */
94         0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
95         0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
96         0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
97         0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
98         0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8,
99         0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
100         0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8,
101         0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0,
102         0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
103         0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0,
104         0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
105         0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
106         0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98,
107         0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
108         0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
109         0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
110         0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
111         0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
112         0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68,
113         0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
114         0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
115         0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
116         0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48,
117         0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
118         0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
119         0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
120         0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
121         0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
122         0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
123         0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
124         0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
125         0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
126         /* bg = fg = 1 */
127         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
128         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
129         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
135         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
136         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
137         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
139         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
145         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
147         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
148         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
149         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
150         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
151         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
152         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
153         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
154         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
155         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
156         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
158         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
159     };
160     
161     void fbcon_afb_setup(struct display *p)
162     {
163         if (p->line_length)
164     	p->next_line = p->line_length;
165         else
166     	p->next_line = p->var.xres_virtual>>3;
167         p->next_plane = p->var.yres_virtual*p->next_line;
168     }
169     
170     void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
171     		     int height, int width)
172     {
173         u8 *src, *dest, *src0, *dest0;
174         u_short i, j;
175     
176         if (sx == 0 && dx == 0 && width == p->next_line) {
177     	src = p->screen_base+sy*fontheight(p)*width;
178     	dest = p->screen_base+dy*fontheight(p)*width;
179     	i = p->var.bits_per_pixel;
180     	do {
181     	    fb_memmove(dest, src, height*fontheight(p)*width);
182     	    src += p->next_plane;
183     	    dest += p->next_plane;
184     	} while (--i);
185         } else if (dy <= sy) {
186     	src0 = p->screen_base+sy*fontheight(p)*p->next_line+sx;
187     	dest0 = p->screen_base+dy*fontheight(p)*p->next_line+dx;
188     	i = p->var.bits_per_pixel;
189     	do {
190     	    src = src0;
191     	    dest = dest0;
192     	    j = height*fontheight(p);
193     	    do {
194     	        fb_memmove(dest, src, width);
195     	        src += p->next_line;
196     	        dest += p->next_line;
197     	    } while (--j);
198     	    src0 += p->next_plane;
199     	    dest0 += p->next_plane;
200     	} while (--i);
201         } else {
202     	src0 = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx;
203     	dest0 = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx;
204     	i = p->var.bits_per_pixel;
205     	do {
206     	    src = src0;
207     	    dest = dest0;
208     	    j = height*fontheight(p);
209     	    do {
210     	        src -= p->next_line;
211     	        dest -= p->next_line;
212     	        fb_memmove(dest, src, width);
213     	    } while (--j);
214     	    src0 += p->next_plane;
215     	    dest0 += p->next_plane;
216     	} while (--i);
217         }
218     }
219     
220     void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
221     		     int height, int width)
222     {
223         u8 *dest, *dest0;
224         u_short i, j;
225         int bg;
226     
227         dest0 = p->screen_base+sy*fontheight(p)*p->next_line+sx;
228     
229         bg = attr_bgcol_ec(p,conp);
230         i = p->var.bits_per_pixel;
231         do {
232     	dest = dest0;
233     	j = height*fontheight(p);
234     	do {
235     	    if (bg & 1)
236     	        fb_memset255(dest, width);
237     	    else
238     	        fb_memclear(dest, width);
239     	    dest += p->next_line;
240     	} while (--j);
241     	bg >>= 1;
242     	dest0 += p->next_plane;
243         } while (--i);
244     }
245     
246     void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy,
247     		    int xx)
248     {
249         u8 *dest, *dest0, *cdat, *cdat0, *expand;
250         u_short i, j;
251         int fg, bg;
252     
253         dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
254         cdat0 = p->fontdata+(c&p->charmask)*fontheight(p);
255         fg = attr_fgcol(p,c);
256         bg = attr_bgcol(p,c);
257     
258         i = p->var.bits_per_pixel;
259         do {
260     	dest = dest0;
261     	cdat = cdat0;
262     	expand = expand_table;
263     	if (bg & 1)
264     	    expand += 512;
265     	if (fg & 1)
266     	    expand += 256;
267     	j = fontheight(p);
268     	do {
269     	    *dest = expand[*cdat++];
270     	    dest += p->next_line;
271     	} while (--j);
272     	bg >>= 1;
273     	fg >>= 1;
274     	dest0 += p->next_plane;
275         } while (--i);
276     }
277     
278         /*
279          *  I've split the console character loop in two parts
280          *  (cfr. fbcon_putcs_ilbm())
281          */
282     
283     void fbcon_afb_putcs(struct vc_data *conp, struct display *p, 
284     		     const unsigned short *s, int count, int yy, int xx)
285     {
286         u8 *dest, *dest0, *dest1, *expand;
287         u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
288         u_short i, j;
289         u16 c1, c2, c3, c4;
290         int fg0, bg0, fg, bg;
291     
292         dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
293         fg0 = attr_fgcol(p, scr_readw(s));
294         bg0 = attr_bgcol(p, scr_readw(s));
295     
296         while (count--)
297     	if (xx&3 || count < 3) {	/* Slow version */
298     	    c1 = scr_readw(s++) & p->charmask;
299     	    dest1 = dest0++;
300     	    xx++;
301     
302     	    cdat10 = p->fontdata+c1*fontheight(p);
303     	    fg = fg0;
304     	    bg = bg0;
305     
306     	    i = p->var.bits_per_pixel;
307     	    do {
308     	        dest = dest1;
309     	        cdat1 = cdat10;
310     		expand = expand_table;
311     		if (bg & 1)
312     		    expand += 512;
313     		if (fg & 1)
314     		    expand += 256;
315     		j = fontheight(p);
316     		do {
317     		    *dest = expand[*cdat1++];
318     		    dest += p->next_line;
319     	        } while (--j);
320     	        bg >>= 1;
321     	        fg >>= 1;
322     		dest1 += p->next_plane;
323     	    } while (--i);
324     	} else {			/* Fast version */
325     	    c1 = scr_readw(&s[0]) & p->charmask;
326     	    c2 = scr_readw(&s[1]) & p->charmask;
327     	    c3 = scr_readw(&s[2]) & p->charmask;
328     	    c4 = scr_readw(&s[3]) & p->charmask;
329     
330     	    dest1 = dest0;
331     	    cdat10 = p->fontdata+c1*fontheight(p);
332     	    cdat20 = p->fontdata+c2*fontheight(p);
333     	    cdat30 = p->fontdata+c3*fontheight(p);
334     	    cdat40 = p->fontdata+c4*fontheight(p);
335     	    fg = fg0;
336     	    bg = bg0;
337     
338     	    i = p->var.bits_per_pixel;
339     	    do {
340     	        dest = dest1;
341     	        cdat1 = cdat10;
342     	        cdat2 = cdat20;
343     	        cdat3 = cdat30;
344     	        cdat4 = cdat40;
345     		expand = expand_table;
346     		if (bg & 1)
347     		    expand += 512;
348     		if (fg & 1)
349     		    expand += 256;
350     		j = fontheight(p);
351     	        do {
352     #if defined(__BIG_ENDIAN)
353     		    *(u32 *)dest = expand[*cdat1++]<<24 |
354     				   expand[*cdat2++]<<16 |
355     				   expand[*cdat3++]<<8 |
356     				   expand[*cdat4++];
357     #elif defined(__LITTLE_ENDIAN)
358     		    *(u32 *)dest = expand[*cdat1++] |
359     				   expand[*cdat2++]<<8 |
360     				   expand[*cdat3++]<<16 |
361     				   expand[*cdat4++]<<24;
362     #else
363     #error FIXME: No endianness??
364     #endif
365     		    dest += p->next_line;
366     	        } while (--j);
367     	        bg >>= 1;
368     	        fg >>= 1;
369     		dest1 += p->next_plane;
370     	    } while (--i);
371     	    s += 4;
372     	    dest0 += 4;
373     	    xx += 4;
374     	    count -= 3;
375     	}
376     }
377     
378     void fbcon_afb_revc(struct display *p, int xx, int yy)
379     {
380         u8 *dest, *dest0;
381         u_short i, j;
382         int mask;
383     
384         dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
385         mask = p->fgcol ^ p->bgcol;
386     
387         /*
388          *  This should really obey the individual character's
389          *  background and foreground colors instead of simply
390          *  inverting.
391          */
392     
393         i = p->var.bits_per_pixel;
394         do {
395     	if (mask & 1) {
396     	    dest = dest0;
397     	    j = fontheight(p);
398     	    do {
399     	        *dest = ~*dest;
400     		dest += p->next_line;
401     	    } while (--j);
402     	}
403     	mask >>= 1;
404     	dest0 += p->next_plane;
405         } while (--i);
406     }
407     
408     
409         /*
410          *  `switch' for the low level operations
411          */
412     
413     struct display_switch fbcon_afb = {
414         setup:		fbcon_afb_setup,
415         bmove:		fbcon_afb_bmove,
416         clear:		fbcon_afb_clear,
417         putc:		fbcon_afb_putc,
418         putcs:		fbcon_afb_putcs,
419         revc:		fbcon_afb_revc,
420         fontwidthmask:	FONTWIDTH(8)
421     };
422     
423     
424     #ifdef MODULE
425     MODULE_LICENSE("GPL");
426     
427     int init_module(void)
428     {
429         return 0;
430     }
431     
432     void cleanup_module(void)
433     {}
434     #endif /* MODULE */
435     
436     
437         /*
438          *  Visible symbols for modules
439          */
440     
441     EXPORT_SYMBOL(fbcon_afb);
442     EXPORT_SYMBOL(fbcon_afb_setup);
443     EXPORT_SYMBOL(fbcon_afb_bmove);
444     EXPORT_SYMBOL(fbcon_afb_clear);
445     EXPORT_SYMBOL(fbcon_afb_putc);
446     EXPORT_SYMBOL(fbcon_afb_putcs);
447     EXPORT_SYMBOL(fbcon_afb_revc);
448