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, int dst_idx,
29 const unsigned long *src, int 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 >> right, *dst, first);
90 } else if (src_idx+n <= bits) {
91
92 *dst = comp(*src << left, *dst, first);
93 } else {
94
95 d0 = *src++;
96 d1 = *src;
97 *dst = comp(d0 << left | d1 >> right, *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 >> right, *dst, first);
113 dst++;
114 n -= bits - dst_idx;
115 } else {
116
117 d1 = *src++;
118 *dst = comp(d0 << left | *dst >> right, *dst, first);
119 d0 = d1;
120 dst++;
121 n -= bits - dst_idx;
122 }
123
124
125 m = n % bits;
126 n /= bits;
127 while (n >= 4) {
128 d1 = *src++;
129 *dst++ = d0 << left | d1 >> right;
130 d0 = d1;
131 d1 = *src++;
132 *dst++ = d0 << left | d1 >> right;
133 d0 = d1;
134 d1 = *src++;
135 *dst++ = d0 << left | d1 >> right;
136 d0 = d1;
137 d1 = *src++;
138 *dst++ = d0 << left | d1 >> right;
139 d0 = d1;
140 n -= 4;
141 }
142 while (n--) {
143 d1 = *src++;
144 *dst++ = d0 << left | d1 >> right;
145 d0 = d1;
146 }
147
148
149 if (last) {
150 if (m <= right) {
151
152 *dst = comp(d0 << left, *dst, last);
153 } else {
154
155 d1 = *src;
156 *dst = comp(d0 << left | d1 >> right,
157 *dst, last);
158 }
159 }
160 }
161 }
162}
163
164
165
166
167
168static void
169bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
170 const unsigned long *src, int src_idx, int bits, unsigned n)
171{
172 unsigned long first, last;
173 int shift;
174
175 dst += (n-1)/bits;
176 src += (n-1)/bits;
177 if ((n-1) % bits) {
178 dst_idx += (n-1) % bits;
179 dst += dst_idx >> (ffs(bits) - 1);
180 dst_idx &= bits - 1;
181 src_idx += (n-1) % bits;
182 src += src_idx >> (ffs(bits) - 1);
183 src_idx &= bits - 1;
184 }
185
186 shift = dst_idx-src_idx;
187
188 first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
189 last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
190
191 if (!shift) {
192
193 if ((unsigned long)dst_idx+1 >= n) {
194
195 if (last)
196 first &= last;
197 *dst = comp(*src, *dst, first);
198 } else {
199
200
201
202 if (first != ~0UL) {
203 *dst = comp(*src, *dst, first);
204 dst--;
205 src--;
206 n -= dst_idx+1;
207 }
208
209
210 n /= bits;
211 while (n >= 8) {
212 *dst-- = *src--;
213 *dst-- = *src--;
214 *dst-- = *src--;
215 *dst-- = *src--;
216 *dst-- = *src--;
217 *dst-- = *src--;
218 *dst-- = *src--;
219 *dst-- = *src--;
220 n -= 8;
221 }
222 while (n--)
223 *dst-- = *src--;
224
225 if (last)
226 *dst = comp(*src, *dst, last);
227 }
228 } else {
229
230
231 int const left = -shift & (bits-1);
232 int const right = shift & (bits-1);
233
234 if ((unsigned long)dst_idx+1 >= n) {
235
236 if (last)
237 first &= last;
238 if (shift < 0) {
239
240 *dst = comp(*src << left, *dst, first);
241 } else if (1+(unsigned long)src_idx >= n) {
242
243 *dst = comp(*src >> right, *dst, first);
244 } else {
245
246 *dst = comp(*src >> right | *(src-1) << left,
247 *dst, first);
248 }
249 } else {
250
251
252
253
254
255
256
257 unsigned long d0, d1;
258 int m;
259
260 d0 = *src--;
261
262 if (shift < 0) {
263
264 *dst = comp(d0 << left, *dst, first);
265 } else {
266
267 d1 = *src--;
268 *dst = comp(d0 >> right | d1 << left, *dst,
269 first);
270 d0 = d1;
271 }
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 >> right | d1 << left;
281 d0 = d1;
282 d1 = *src--;
283 *dst-- = d0 >> right | d1 << left;
284 d0 = d1;
285 d1 = *src--;
286 *dst-- = d0 >> right | d1 << left;
287 d0 = d1;
288 d1 = *src--;
289 *dst-- = d0 >> right | d1 << left;
290 d0 = d1;
291 n -= 4;
292 }
293 while (n--) {
294 d1 = *src--;
295 *dst-- = d0 >> right | d1 << left;
296 d0 = d1;
297 }
298
299
300 if (last) {
301 if (m <= left) {
302
303 *dst = comp(d0 >> right, *dst, last);
304 } else {
305
306 d1 = *src;
307 *dst = comp(d0 >> right | d1 << left,
308 *dst, last);
309 }
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 *dst = NULL, *src = NULL;
321 int bits = BITS_PER_LONG, bytes = bits >> 3;
322 int 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 dst = src = (unsigned long *)((unsigned long)p->screen_base &
338 ~(bytes-1));
339 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
340
341 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
342 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
343
344 if (p->fbops->fb_sync)
345 p->fbops->fb_sync(p);
346
347 if (rev_copy) {
348 while (height--) {
349 dst_idx -= bits_per_line;
350 src_idx -= bits_per_line;
351 dst += dst_idx >> (ffs(bits) - 1);
352 dst_idx &= (bytes - 1);
353 src += src_idx >> (ffs(bits) - 1);
354 src_idx &= (bytes - 1);
355 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
356 width*p->var.bits_per_pixel);
357 }
358 } else {
359 while (height--) {
360 dst += dst_idx >> (ffs(bits) - 1);
361 dst_idx &= (bytes - 1);
362 src += src_idx >> (ffs(bits) - 1);
363 src_idx &= (bytes - 1);
364 bitcpy(p, dst, dst_idx, src, src_idx, bits,
365 width*p->var.bits_per_pixel);
366 dst_idx += bits_per_line;
367 src_idx += bits_per_line;
368 }
369 }
370}
371
372EXPORT_SYMBOL(sys_copyarea);
373
374MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
375MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
376MODULE_LICENSE("GPL");
377
378