clean
[linux-2.4.21-pre4.git] / 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     c1 = scr_readw(s);
294     fg0 = attr_fgcol(p, c1);
295     bg0 = attr_bgcol(p, c1);
296
297     while (count--)
298         if (xx&3 || count < 3) {        /* Slow version */
299             c1 = scr_readw(s++) & p->charmask;
300             dest1 = dest0++;
301             xx++;
302
303             cdat10 = p->fontdata+c1*fontheight(p);
304             fg = fg0;
305             bg = bg0;
306
307             i = p->var.bits_per_pixel;
308             do {
309                 dest = dest1;
310                 cdat1 = cdat10;
311                 expand = expand_table;
312                 if (bg & 1)
313                     expand += 512;
314                 if (fg & 1)
315                     expand += 256;
316                 j = fontheight(p);
317                 do {
318                     *dest = expand[*cdat1++];
319                     dest += p->next_line;
320                 } while (--j);
321                 bg >>= 1;
322                 fg >>= 1;
323                 dest1 += p->next_plane;
324             } while (--i);
325         } else {                        /* Fast version */
326             c1 = scr_readw(&s[0]) & p->charmask;
327             c2 = scr_readw(&s[1]) & p->charmask;
328             c3 = scr_readw(&s[2]) & p->charmask;
329             c4 = scr_readw(&s[3]) & p->charmask;
330
331             dest1 = dest0;
332             cdat10 = p->fontdata+c1*fontheight(p);
333             cdat20 = p->fontdata+c2*fontheight(p);
334             cdat30 = p->fontdata+c3*fontheight(p);
335             cdat40 = p->fontdata+c4*fontheight(p);
336             fg = fg0;
337             bg = bg0;
338
339             i = p->var.bits_per_pixel;
340             do {
341                 dest = dest1;
342                 cdat1 = cdat10;
343                 cdat2 = cdat20;
344                 cdat3 = cdat30;
345                 cdat4 = cdat40;
346                 expand = expand_table;
347                 if (bg & 1)
348                     expand += 512;
349                 if (fg & 1)
350                     expand += 256;
351                 j = fontheight(p);
352                 do {
353 #if defined(__BIG_ENDIAN)
354                     *(u32 *)dest = expand[*cdat1++]<<24 |
355                                    expand[*cdat2++]<<16 |
356                                    expand[*cdat3++]<<8 |
357                                    expand[*cdat4++];
358 #elif defined(__LITTLE_ENDIAN)
359                     *(u32 *)dest = expand[*cdat1++] |
360                                    expand[*cdat2++]<<8 |
361                                    expand[*cdat3++]<<16 |
362                                    expand[*cdat4++]<<24;
363 #else
364 #error FIXME: No endianness??
365 #endif
366                     dest += p->next_line;
367                 } while (--j);
368                 bg >>= 1;
369                 fg >>= 1;
370                 dest1 += p->next_plane;
371             } while (--i);
372             s += 4;
373             dest0 += 4;
374             xx += 4;
375             count -= 3;
376         }
377 }
378
379 void fbcon_afb_revc(struct display *p, int xx, int yy)
380 {
381     u8 *dest, *dest0;
382     u_short i, j;
383     int mask;
384
385     dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
386     mask = p->fgcol ^ p->bgcol;
387
388     /*
389      *  This should really obey the individual character's
390      *  background and foreground colors instead of simply
391      *  inverting.
392      */
393
394     i = p->var.bits_per_pixel;
395     do {
396         if (mask & 1) {
397             dest = dest0;
398             j = fontheight(p);
399             do {
400                 *dest = ~*dest;
401                 dest += p->next_line;
402             } while (--j);
403         }
404         mask >>= 1;
405         dest0 += p->next_plane;
406     } while (--i);
407 }
408
409
410     /*
411      *  `switch' for the low level operations
412      */
413
414 struct display_switch fbcon_afb = {
415     setup:              fbcon_afb_setup,
416     bmove:              fbcon_afb_bmove,
417     clear:              fbcon_afb_clear,
418     putc:               fbcon_afb_putc,
419     putcs:              fbcon_afb_putcs,
420     revc:               fbcon_afb_revc,
421     fontwidthmask:      FONTWIDTH(8)
422 };
423
424
425 #ifdef MODULE
426 MODULE_LICENSE("GPL");
427
428 int init_module(void)
429 {
430     return 0;
431 }
432
433 void cleanup_module(void)
434 {}
435 #endif /* MODULE */
436
437
438     /*
439      *  Visible symbols for modules
440      */
441
442 EXPORT_SYMBOL(fbcon_afb);
443 EXPORT_SYMBOL(fbcon_afb_setup);
444 EXPORT_SYMBOL(fbcon_afb_bmove);
445 EXPORT_SYMBOL(fbcon_afb_clear);
446 EXPORT_SYMBOL(fbcon_afb_putc);
447 EXPORT_SYMBOL(fbcon_afb_putcs);
448 EXPORT_SYMBOL(fbcon_afb_revc);