Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
468 giacomo 1
/*
2
 *  Generic function for frame buffer with packed pixels of any depth.
3
 *
4
 *      Copyright (C)  June 1999 James Simmons
5
 *
6
 *  This file is subject to the terms and conditions of the GNU General Public
7
 *  License.  See the file COPYING in the main directory of this archive for
8
 *  more details.
9
 *
10
 * NOTES:
11
 *
12
 *  This is for cfb packed pixels. Iplan and such are incorporated in the
13
 *  drivers that need them.
14
 *
15
 *  FIXME
16
 *  The code for 24 bit is horrible. It copies byte by byte size instead of
17
 *  longs like the other sizes. Needs to be optimized.
18
 *
19
 *  Also need to add code to deal with cards endians that are different than
20
 *  the native cpu endians. I also need to deal with MSB position in the word.
21
 *  
22
 */
23
 
24
#include <linuxcomp.h>
25
 
26
#include <linux/config.h>
27
#include <linux/module.h>
28
#include <linux/kernel.h>
29
#include <linux/string.h>
30
#include <linux/fb.h>
31
#include <linux/slab.h>
32
#include <asm/types.h>
33
#include <asm/io.h>
34
 
35
#define LONG_MASK  (BITS_PER_LONG - 1)
36
 
37
#if BITS_PER_LONG == 32
38
#define FB_WRITEL fb_writel
39
#define FB_READL  fb_readl
40
#define SHIFT_PER_LONG 5
41
#define BYTES_PER_LONG 4
42
#else
43
#define FB_WRITEL fb_writeq
44
#define FB_READL  fb_readq
45
#define SHIFT_PER_LONG 6
46
#define BYTES_PER_LONG 8
47
#endif
48
 
49
static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
50
                   int src_idx, unsigned long n)
51
{
52
        unsigned long first, last;
53
        int shift = dst_idx-src_idx, left, right;
54
        unsigned long d0, d1;
55
        int m;
56
 
57
        if (!n)
58
                return;
59
 
60
        shift = dst_idx-src_idx;
61
        first = ~0UL >> dst_idx;
62
        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
63
 
64
        if (!shift) {
65
                // Same alignment for source and dest
66
 
67
                if (dst_idx+n <= BITS_PER_LONG) {
68
                        // Single word
69
                        if (last)
70
                                first &= last;
71
                        FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
72
                } else {
73
                        // Multiple destination words
74
                        // Leading bits
75
                        if (first) {
76
 
77
                                FB_WRITEL((FB_READL(src) & first) |
78
                                          (FB_READL(dst) & ~first), dst);
79
                                dst++;
80
                                src++;
81
                                n -= BITS_PER_LONG-dst_idx;
82
                        }
83
 
84
                        // Main chunk
85
                        n /= BITS_PER_LONG;
86
                        while (n >= 8) {
87
                                FB_WRITEL(FB_READL(src++), dst++);
88
                                FB_WRITEL(FB_READL(src++), dst++);
89
                                FB_WRITEL(FB_READL(src++), dst++);
90
                                FB_WRITEL(FB_READL(src++), dst++);
91
                                FB_WRITEL(FB_READL(src++), dst++);
92
                                FB_WRITEL(FB_READL(src++), dst++);
93
                                FB_WRITEL(FB_READL(src++), dst++);
94
                                FB_WRITEL(FB_READL(src++), dst++);
95
                                n -= 8;
96
                        }
97
                        while (n--)
98
                                FB_WRITEL(FB_READL(src++), dst++);
99
                        // Trailing bits
100
                        if (last)
101
                                FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
102
                }
103
        } else {
104
                // Different alignment for source and dest
105
 
106
                right = shift & (BITS_PER_LONG-1);
107
                left = -shift & (BITS_PER_LONG-1);
108
 
109
                if (dst_idx+n <= BITS_PER_LONG) {
110
                        // Single destination word
111
                        if (last)
112
                                first &= last;
113
                        if (shift > 0) {
114
                                // Single source word
115
                                FB_WRITEL(((FB_READL(src) >> right) & first) |
116
                                          (FB_READL(dst) & ~first), dst);
117
                        } else if (src_idx+n <= BITS_PER_LONG) {
118
                                // Single source word
119
                                FB_WRITEL(((FB_READL(src) << left) & first) |
120
                                          (FB_READL(dst) & ~first), dst);
121
                        } else {
122
                                // 2 source words
123
                                d0 = FB_READL(src++);
124
                                d1 = FB_READL(src);
125
                                FB_WRITEL(((d0<<left | d1>>right) & first) |
126
                                          (FB_READL(dst) & ~first), dst);
127
                        }
128
                } else {
129
                        // Multiple destination words
130
                        d0 = FB_READL(src++);
131
                        // Leading bits
132
                        if (shift > 0) {
133
                                // Single source word
134
                                FB_WRITEL(((d0 >> right) & first) |
135
                                          (FB_READL(dst) & ~first), dst);
136
                                dst++;
137
                                n -= BITS_PER_LONG-dst_idx;
138
                        } else {
139
                                // 2 source words
140
                                d1 = FB_READL(src++);
141
                                FB_WRITEL(((d0<<left | d1>>right) & first) |
142
                                          (FB_READL(dst) & ~first), dst);
143
                                d0 = d1;
144
                                dst++;
145
                                n -= BITS_PER_LONG-dst_idx;
146
                        }
147
 
148
                        // Main chunk
149
                        m = n % BITS_PER_LONG;
150
                        n /= BITS_PER_LONG;
151
                        while (n >= 4) {
152
                                d1 = FB_READL(src++);
153
                                FB_WRITEL(d0 << left | d1 >> right, dst++);
154
                                d0 = d1;
155
                                d1 = FB_READL(src++);
156
                                FB_WRITEL(d0 << left | d1 >> right, dst++);
157
                                d0 = d1;
158
                                d1 = FB_READL(src++);
159
                                FB_WRITEL(d0 << left | d1 >> right, dst++);
160
                                d0 = d1;
161
                                d1 = FB_READL(src++);
162
                                FB_WRITEL(d0 << left | d1 >> right, dst++);
163
                                d0 = d1;
164
                                n -= 4;
165
                        }
166
                        while (n--) {
167
                                d1 = FB_READL(src++);
168
                                FB_WRITEL(d0 << left | d1 >> right, dst++);
169
                                d0 = d1;
170
                        }
171
 
172
                        // Trailing bits
173
                        if (last) {
174
                                if (m <= right) {
175
                                        // Single source word
176
                                        FB_WRITEL(((d0 << left) & last) |
177
                                                  (FB_READL(dst) & ~last),
178
                                                  dst);
179
                                } else {
180
                                        // 2 source words
181
                                        d1 = FB_READL(src);
182
                                        FB_WRITEL(((d0<<left | d1>>right) &
183
                                                   last) | (FB_READL(dst) &
184
                                                            ~last), dst);
185
                                }
186
                        }
187
                }
188
        }
189
}
190
 
191
static void bitcpy_rev(unsigned long *dst, int dst_idx,
192
                       const unsigned long *src, int src_idx, unsigned long n)
193
{
194
        unsigned long first, last;
195
        int shift = dst_idx-src_idx, left, right;
196
        unsigned long d0, d1;
197
        int m;
198
 
199
        if (!n)
200
                return;
201
 
202
        dst += (n-1)/BITS_PER_LONG;
203
        src += (n-1)/BITS_PER_LONG;
204
        if ((n-1) % BITS_PER_LONG) {
205
                dst_idx += (n-1) % BITS_PER_LONG;
206
                dst += dst_idx >> SHIFT_PER_LONG;
207
                dst_idx &= BITS_PER_LONG-1;
208
                src_idx += (n-1) % BITS_PER_LONG;
209
                src += src_idx >> SHIFT_PER_LONG;
210
                src_idx &= BITS_PER_LONG-1;
211
        }
212
 
213
        shift = dst_idx-src_idx;
214
        first = ~0UL << (BITS_PER_LONG-1-dst_idx);
215
        last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
216
 
217
        if (!shift) {
218
                // Same alignment for source and dest
219
 
220
                if ((unsigned long)dst_idx+1 >= n) {
221
                        // Single word
222
                        if (last)
223
                                first &= last;
224
                        FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
225
                } else {
226
                        // Multiple destination words
227
                        // Leading bits
228
                        if (first) {
229
                                FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
230
                                dst--;
231
                                src--;
232
                                n -= dst_idx+1;
233
                        }
234
 
235
                        // Main chunk
236
                        n /= BITS_PER_LONG;
237
                        while (n >= 8) {
238
                                FB_WRITEL(FB_READL(src--), dst--);
239
                                FB_WRITEL(FB_READL(src--), dst--);
240
                                FB_WRITEL(FB_READL(src--), dst--);
241
                                FB_WRITEL(FB_READL(src--), dst--);
242
                                FB_WRITEL(FB_READL(src--), dst--);
243
                                FB_WRITEL(FB_READL(src--), dst--);
244
                                FB_WRITEL(FB_READL(src--), dst--);
245
                                FB_WRITEL(FB_READL(src--), dst--);
246
                                n -= 8;
247
                        }
248
                        while (n--)
249
                                FB_WRITEL(FB_READL(src--), dst--);
250
 
251
                        // Trailing bits
252
                        if (last)
253
                                FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
254
                }
255
        } else {
256
                // Different alignment for source and dest
257
 
258
                right = shift & (BITS_PER_LONG-1);
259
                left = -shift & (BITS_PER_LONG-1);
260
 
261
                if ((unsigned long)dst_idx+1 >= n) {
262
                        // Single destination word
263
                        if (last)
264
                                first &= last;
265
                        if (shift < 0) {
266
                                // Single source word
267
                                FB_WRITEL((FB_READL(src) << left & first) |
268
                                          (FB_READL(dst) & ~first), dst);
269
                        } else if (1+(unsigned long)src_idx >= n) {
270
                                // Single source word
271
                                FB_WRITEL(((FB_READL(src) >> right) & first) |
272
                                          (FB_READL(dst) & ~first), dst);
273
                        } else {
274
                                // 2 source words
275
                                d0 = FB_READL(src--);
276
                                d1 = FB_READL(src);
277
                                FB_WRITEL(((d0>>right | d1<<left) & first) |
278
                                          (FB_READL(dst) & ~first), dst);
279
                        }
280
                } else {
281
                        // Multiple destination words
282
                        d0 = FB_READL(src--);
283
                        // Leading bits
284
                        if (shift < 0) {
285
                                // Single source word
286
                                FB_WRITEL(((d0 << left) & first) |
287
                                          (FB_READL(dst) & ~first), dst);
288
                                dst--;
289
                                n -= dst_idx+1;
290
                        } else {
291
                                // 2 source words
292
                                d1 = FB_READL(src--);
293
                                FB_WRITEL(((d0>>right | d1<<left) & first) |
294
                                          (FB_READL(dst) & ~first), dst);
295
                                d0 = d1;
296
                                dst--;
297
                                n -= dst_idx+1;
298
                        }
299
 
300
                        // Main chunk
301
                        m = n % BITS_PER_LONG;
302
                        n /= BITS_PER_LONG;
303
                        while (n >= 4) {
304
                                d1 = FB_READL(src--);
305
                                FB_WRITEL(d0 >> right | d1 << left, dst--);
306
                                d0 = d1;
307
                                d1 = FB_READL(src--);
308
                                FB_WRITEL(d0 >> right | d1 << left, dst--);
309
                                d0 = d1;
310
                                d1 = FB_READL(src--);
311
                                FB_WRITEL(d0 >> right | d1 << left, dst--);
312
                                d0 = d1;
313
                                d1 = FB_READL(src--);
314
                                FB_WRITEL(d0 >> right | d1 << left, dst--);
315
                                d0 = d1;
316
                                n -= 4;
317
                        }
318
                        while (n--) {
319
                                d1 = FB_READL(src--);
320
                                FB_WRITEL(d0 >> right | d1 << left, dst--);
321
                                d0 = d1;
322
                        }
323
 
324
                        // Trailing bits
325
                        if (last) {
326
                                if (m <= left) {
327
                                        // Single source word
328
                                        FB_WRITEL(((d0 >> right) & last) |
329
                                                  (FB_READL(dst) & ~last),
330
                                                  dst);
331
                                } else {
332
                                        // 2 source words
333
                                        d1 = FB_READL(src);
334
                                        FB_WRITEL(((d0>>right | d1<<left) &
335
                                                   last) | (FB_READL(dst) &
336
                                                            ~last), dst);
337
                                }
338
                        }
339
                }
340
        }
341
}
342
 
343
void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
344
{
345
        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
346
        u32 height = area->height, width = area->width;
347
        int x2, y2, old_dx, old_dy, vxres, vyres;
348
        unsigned long next_line = p->fix.line_length;
349
        int dst_idx = 0, src_idx = 0, rev_copy = 0;
350
        unsigned long *dst = NULL, *src = NULL;
351
 
352
        /* We want rotation but lack hardware to do it for us. */
353
        if (!p->fbops->fb_rotate && p->var.rotate) {
354
        }      
355
 
356
        vxres = p->var.xres_virtual;
357
        vyres = p->var.yres_virtual;
358
 
359
        if (area->dx > vxres || area->sx > vxres ||
360
            area->dy > vyres || area->sy > vyres)
361
                return;
362
 
363
        /* clip the destination */
364
        old_dx = area->dx;
365
        old_dy = area->dy;
366
 
367
        /*
368
         * We could use hardware clipping but on many cards you get around
369
         * hardware clipping by writing to framebuffer directly.
370
         */
371
        x2 = area->dx + area->width;
372
        y2 = area->dy + area->height;
373
        dx = area->dx > 0 ? area->dx : 0;
374
        dy = area->dy > 0 ? area->dy : 0;
375
        x2 = x2 < vxres ? x2 : vxres;
376
        y2 = y2 < vyres ? y2 : vyres;
377
        width = x2 - dx;
378
        height = y2 - dy;
379
 
380
        /* update sx1,sy1 */
381
        sx += (dx - old_dx);
382
        sy += (dy - old_dy);
383
 
384
        /* the source must be completely inside the virtual screen */
385
        if (sx < 0 || sy < 0 ||
386
            (sx + width) > vxres ||
387
            (sy + height) > vyres)
388
                return;
389
 
390
        if ((dy == sy && dx > sx) ||   
391
            (dy > sy)) {
392
                dy += height;
393
                sy += height;
394
                rev_copy = 1;
395
        }
396
 
397
        dst = src = (unsigned long *)((unsigned long)p->screen_base &
398
                                      ~(BYTES_PER_LONG-1));
399
        dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1);
400
        dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel;
401
        src_idx += sy*next_line*8 + sx*p->var.bits_per_pixel;
402
 
403
        if (p->fbops->fb_sync)
404
                p->fbops->fb_sync(p);
405
        if (rev_copy) {
406
                while (height--) {
407
                        dst_idx -= next_line*8;
408
                        src_idx -= next_line*8;
409
                        dst += dst_idx >> SHIFT_PER_LONG;
410
                        dst_idx &= (BYTES_PER_LONG-1);
411
                        src += src_idx >> SHIFT_PER_LONG;
412
                        src_idx &= (BYTES_PER_LONG-1);
413
                        bitcpy_rev(dst, dst_idx, src, src_idx,
414
                                   width*p->var.bits_per_pixel);
415
                }      
416
        } else {
417
                while (height--) {
418
                        dst += dst_idx >> SHIFT_PER_LONG;
419
                        dst_idx &= (BYTES_PER_LONG-1);
420
                        src += src_idx >> SHIFT_PER_LONG;
421
                        src_idx &= (BYTES_PER_LONG-1);
422
                        bitcpy(dst, dst_idx, src, src_idx,
423
                               width*p->var.bits_per_pixel);
424
                        dst_idx += next_line*8;
425
                        src_idx += next_line*8;
426
                }      
427
        }
428
}
429
 
430
EXPORT_SYMBOL(cfb_copyarea);
431
 
432
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
433
MODULE_DESCRIPTION("Generic software accelerated copyarea");
434
MODULE_LICENSE("GPL");
435