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