1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/module.h>
26#include <linux/kernel.h>
27#include <linux/string.h>
28#include <linux/fb.h>
29#include <linux/slab.h>
30#include <asm/types.h>
31#include <asm/io.h>
32#include "fb_draw.h"
33
34#if BITS_PER_LONG == 32
35# define FB_WRITEL fb_writel
36# define FB_READL fb_readl
37#else
38# define FB_WRITEL fb_writeq
39# define FB_READL fb_readq
40#endif
41
42
43
44
45
46static void
47bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
48 const unsigned long __iomem *src, int src_idx, int bits,
49 unsigned n, u32 bswapmask)
50{
51 unsigned long first, last;
52 int const shift = dst_idx-src_idx;
53 int left, right;
54
55 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
56 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
57
58 if (!shift) {
59
60
61 if (dst_idx+n <= bits) {
62
63 if (last)
64 first &= last;
65 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
66 } else {
67
68
69
70 if (first != ~0UL) {
71 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
72 dst++;
73 src++;
74 n -= bits - dst_idx;
75 }
76
77
78 n /= bits;
79 while (n >= 8) {
80 FB_WRITEL(FB_READL(src++), dst++);
81 FB_WRITEL(FB_READL(src++), dst++);
82 FB_WRITEL(FB_READL(src++), dst++);
83 FB_WRITEL(FB_READL(src++), dst++);
84 FB_WRITEL(FB_READL(src++), dst++);
85 FB_WRITEL(FB_READL(src++), dst++);
86 FB_WRITEL(FB_READL(src++), dst++);
87 FB_WRITEL(FB_READL(src++), dst++);
88 n -= 8;
89 }
90 while (n--)
91 FB_WRITEL(FB_READL(src++), dst++);
92
93
94 if (last)
95 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
96 }
97 } else {
98
99 unsigned long d0, d1;
100 int m;
101
102 right = shift & (bits - 1);
103 left = -shift & (bits - 1);
104 bswapmask &= shift;
105
106 if (dst_idx+n <= bits) {
107
108 if (last)
109 first &= last;
110 d0 = FB_READL(src);
111 d0 = fb_rev_pixels_in_long(d0, bswapmask);
112 if (shift > 0) {
113
114 d0 >>= right;
115 } else if (src_idx+n <= bits) {
116
117 d0 <<= left;
118 } else {
119
120 d1 = FB_READL(src + 1);
121 d1 = fb_rev_pixels_in_long(d1, bswapmask);
122 d0 = d0<<left | d1>>right;
123 }
124 d0 = fb_rev_pixels_in_long(d0, bswapmask);
125 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
126 } else {
127
128
129
130
131
132
133 d0 = FB_READL(src++);
134 d0 = fb_rev_pixels_in_long(d0, bswapmask);
135
136 if (shift > 0) {
137
138 d1 = d0;
139 d0 >>= right;
140 dst++;
141 n -= bits - dst_idx;
142 } else {
143
144 d1 = FB_READL(src++);
145 d1 = fb_rev_pixels_in_long(d1, bswapmask);
146
147 d0 = d0<<left | d1>>right;
148 dst++;
149 n -= bits - dst_idx;
150 }
151 d0 = fb_rev_pixels_in_long(d0, bswapmask);
152 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
153 d0 = d1;
154
155
156 m = n % bits;
157 n /= bits;
158 while ((n >= 4) && !bswapmask) {
159 d1 = FB_READL(src++);
160 FB_WRITEL(d0 << left | d1 >> right, dst++);
161 d0 = d1;
162 d1 = FB_READL(src++);
163 FB_WRITEL(d0 << left | d1 >> right, dst++);
164 d0 = d1;
165 d1 = FB_READL(src++);
166 FB_WRITEL(d0 << left | d1 >> right, dst++);
167 d0 = d1;
168 d1 = FB_READL(src++);
169 FB_WRITEL(d0 << left | d1 >> right, dst++);
170 d0 = d1;
171 n -= 4;
172 }
173 while (n--) {
174 d1 = FB_READL(src++);
175 d1 = fb_rev_pixels_in_long(d1, bswapmask);
176 d0 = d0 << left | d1 >> right;
177 d0 = fb_rev_pixels_in_long(d0, bswapmask);
178 FB_WRITEL(d0, dst++);
179 d0 = d1;
180 }
181
182
183 if (last) {
184 if (m <= right) {
185
186 d0 <<= left;
187 } else {
188
189 d1 = FB_READL(src);
190 d1 = fb_rev_pixels_in_long(d1,
191 bswapmask);
192 d0 = d0<<left | d1>>right;
193 }
194 d0 = fb_rev_pixels_in_long(d0, bswapmask);
195 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
196 }
197 }
198 }
199}
200
201
202
203
204
205static void
206bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
207 const unsigned long __iomem *src, int src_idx, int bits,
208 unsigned n, u32 bswapmask)
209{
210 unsigned long first, last;
211 int shift;
212
213 dst += (n-1)/bits;
214 src += (n-1)/bits;
215 if ((n-1) % bits) {
216 dst_idx += (n-1) % bits;
217 dst += dst_idx >> (ffs(bits) - 1);
218 dst_idx &= bits - 1;
219 src_idx += (n-1) % bits;
220 src += src_idx >> (ffs(bits) - 1);
221 src_idx &= bits - 1;
222 }
223
224 shift = dst_idx-src_idx;
225
226 first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
227 last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
228 bswapmask);
229
230 if (!shift) {
231
232
233 if ((unsigned long)dst_idx+1 >= n) {
234
235 if (last)
236 first &= last;
237 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
238 } else {
239
240
241
242 if (first != ~0UL) {
243 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
244 dst--;
245 src--;
246 n -= dst_idx+1;
247 }
248
249
250 n /= bits;
251 while (n >= 8) {
252 FB_WRITEL(FB_READL(src--), dst--);
253 FB_WRITEL(FB_READL(src--), dst--);
254 FB_WRITEL(FB_READL(src--), dst--);
255 FB_WRITEL(FB_READL(src--), dst--);
256 FB_WRITEL(FB_READL(src--), dst--);
257 FB_WRITEL(FB_READL(src--), dst--);
258 FB_WRITEL(FB_READL(src--), dst--);
259 FB_WRITEL(FB_READL(src--), dst--);
260 n -= 8;
261 }
262 while (n--)
263 FB_WRITEL(FB_READL(src--), dst--);
264
265
266 if (last)
267 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
268 }
269 } else {
270
271 unsigned long d0, d1;
272 int m;
273
274 int const left = -shift & (bits-1);
275 int const right = shift & (bits-1);
276 bswapmask &= shift;
277
278 if ((unsigned long)dst_idx+1 >= n) {
279
280 if (last)
281 first &= last;
282 d0 = FB_READL(src);
283 if (shift < 0) {
284
285 d0 <<= left;
286 } else if (1+(unsigned long)src_idx >= n) {
287
288 d0 >>= right;
289 } else {
290
291 d1 = FB_READL(src - 1);
292 d1 = fb_rev_pixels_in_long(d1, bswapmask);
293 d0 = d0>>right | d1<<left;
294 }
295 d0 = fb_rev_pixels_in_long(d0, bswapmask);
296 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
297 } else {
298
299
300
301
302
303
304
305 d0 = FB_READL(src--);
306 d0 = fb_rev_pixels_in_long(d0, bswapmask);
307
308 if (shift < 0) {
309
310 d1 = d0;
311 d0 <<= left;
312 } else {
313
314 d1 = FB_READL(src--);
315 d1 = fb_rev_pixels_in_long(d1, bswapmask);
316 d0 = d0>>right | d1<<left;
317 }
318 d0 = fb_rev_pixels_in_long(d0, bswapmask);
319 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
320 d0 = d1;
321 dst--;
322 n -= dst_idx+1;
323
324
325 m = n % bits;
326 n /= bits;
327 while ((n >= 4) && !bswapmask) {
328 d1 = FB_READL(src--);
329 FB_WRITEL(d0 >> right | d1 << left, dst--);
330 d0 = d1;
331 d1 = FB_READL(src--);
332 FB_WRITEL(d0 >> right | d1 << left, dst--);
333 d0 = d1;
334 d1 = FB_READL(src--);
335 FB_WRITEL(d0 >> right | d1 << left, dst--);
336 d0 = d1;
337 d1 = FB_READL(src--);
338 FB_WRITEL(d0 >> right | d1 << left, dst--);
339 d0 = d1;
340 n -= 4;
341 }
342 while (n--) {
343 d1 = FB_READL(src--);
344 d1 = fb_rev_pixels_in_long(d1, bswapmask);
345 d0 = d0 >> right | d1 << left;
346 d0 = fb_rev_pixels_in_long(d0, bswapmask);
347 FB_WRITEL(d0, dst--);
348 d0 = d1;
349 }
350
351
352 if (last) {
353 if (m <= left) {
354
355 d0 >>= right;
356 } else {
357
358 d1 = FB_READL(src);
359 d1 = fb_rev_pixels_in_long(d1,
360 bswapmask);
361 d0 = d0>>right | d1<<left;
362 }
363 d0 = fb_rev_pixels_in_long(d0, bswapmask);
364 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
365 }
366 }
367 }
368}
369
370void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
371{
372 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
373 u32 height = area->height, width = area->width;
374 unsigned long const bits_per_line = p->fix.line_length*8u;
375 unsigned long __iomem *dst = NULL, *src = NULL;
376 int bits = BITS_PER_LONG, bytes = bits >> 3;
377 int dst_idx = 0, src_idx = 0, rev_copy = 0;
378 u32 bswapmask = fb_compute_bswapmask(p);
379
380 if (p->state != FBINFO_STATE_RUNNING)
381 return;
382
383
384
385 if ((dy == sy && dx > sx) || (dy > sy)) {
386 dy += height;
387 sy += height;
388 rev_copy = 1;
389 }
390
391
392
393 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
394 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
395
396 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
397 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
398
399 if (p->fbops->fb_sync)
400 p->fbops->fb_sync(p);
401
402 if (rev_copy) {
403 while (height--) {
404 dst_idx -= bits_per_line;
405 src_idx -= bits_per_line;
406 dst += dst_idx >> (ffs(bits) - 1);
407 dst_idx &= (bytes - 1);
408 src += src_idx >> (ffs(bits) - 1);
409 src_idx &= (bytes - 1);
410 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
411 width*p->var.bits_per_pixel, bswapmask);
412 }
413 } else {
414 while (height--) {
415 dst += dst_idx >> (ffs(bits) - 1);
416 dst_idx &= (bytes - 1);
417 src += src_idx >> (ffs(bits) - 1);
418 src_idx &= (bytes - 1);
419 bitcpy(p, dst, dst_idx, src, src_idx, bits,
420 width*p->var.bits_per_pixel, bswapmask);
421 dst_idx += bits_per_line;
422 src_idx += bits_per_line;
423 }
424 }
425}
426
427EXPORT_SYMBOL(cfb_copyarea);
428
429MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
430MODULE_DESCRIPTION("Generic software accelerated copyarea");
431MODULE_LICENSE("GPL");
432
433