Root/
1 | /* |
2 | * Generic Bit Block Transfer for frame buffers located in system RAM with |
3 | * packed pixels of any depth. |
4 | * |
5 | * Based almost entirely from cfbcopyarea.c (which is based almost entirely |
6 | * on Geert Uytterhoeven's copyarea routine) |
7 | * |
8 | * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net> |
9 | * |
10 | * This file is subject to the terms and conditions of the GNU General Public |
11 | * License. See the file COPYING in the main directory of this archive for |
12 | * more details. |
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 | * Generic bitwise copy algorithm |
25 | */ |
26 | |
27 | static void |
28 | bitcpy(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 | /* Same alignment for source and dest */ |
40 | if (dst_idx+n <= bits) { |
41 | /* Single word */ |
42 | if (last) |
43 | first &= last; |
44 | *dst = comp(*src, *dst, first); |
45 | } else { |
46 | /* Multiple destination words */ |
47 | /* Leading bits */ |
48 | if (first != ~0UL) { |
49 | *dst = comp(*src, *dst, first); |
50 | dst++; |
51 | src++; |
52 | n -= bits - dst_idx; |
53 | } |
54 | |
55 | /* Main chunk */ |
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 | /* Trailing bits */ |
72 | if (last) |
73 | *dst = comp(*src, *dst, last); |
74 | } |
75 | } else { |
76 | unsigned long d0, d1; |
77 | int m; |
78 | |
79 | /* Different alignment for source and dest */ |
80 | right = shift & (bits - 1); |
81 | left = -shift & (bits - 1); |
82 | |
83 | if (dst_idx+n <= bits) { |
84 | /* Single destination word */ |
85 | if (last) |
86 | first &= last; |
87 | if (shift > 0) { |
88 | /* Single source word */ |
89 | *dst = comp(*src >> right, *dst, first); |
90 | } else if (src_idx+n <= bits) { |
91 | /* Single source word */ |
92 | *dst = comp(*src << left, *dst, first); |
93 | } else { |
94 | /* 2 source words */ |
95 | d0 = *src++; |
96 | d1 = *src; |
97 | *dst = comp(d0 << left | d1 >> right, *dst, |
98 | first); |
99 | } |
100 | } else { |
101 | /* Multiple destination words */ |
102 | /** We must always remember the last value read, |
103 | because in case SRC and DST overlap bitwise (e.g. |
104 | when moving just one pixel in 1bpp), we always |
105 | collect one full long for DST and that might |
106 | overlap with the current long from SRC. We store |
107 | this value in 'd0'. */ |
108 | d0 = *src++; |
109 | /* Leading bits */ |
110 | if (shift > 0) { |
111 | /* Single source word */ |
112 | *dst = comp(d0 >> right, *dst, first); |
113 | dst++; |
114 | n -= bits - dst_idx; |
115 | } else { |
116 | /* 2 source words */ |
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 | /* Main chunk */ |
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 | /* Trailing bits */ |
149 | if (last) { |
150 | if (m <= right) { |
151 | /* Single source word */ |
152 | *dst = comp(d0 << left, *dst, last); |
153 | } else { |
154 | /* 2 source words */ |
155 | d1 = *src; |
156 | *dst = comp(d0 << left | d1 >> right, |
157 | *dst, last); |
158 | } |
159 | } |
160 | } |
161 | } |
162 | } |
163 | |
164 | /* |
165 | * Generic bitwise copy algorithm, operating backward |
166 | */ |
167 | |
168 | static void |
169 | bitcpy_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 | /* Same alignment for source and dest */ |
193 | if ((unsigned long)dst_idx+1 >= n) { |
194 | /* Single word */ |
195 | if (last) |
196 | first &= last; |
197 | *dst = comp(*src, *dst, first); |
198 | } else { |
199 | /* Multiple destination words */ |
200 | |
201 | /* Leading bits */ |
202 | if (first != ~0UL) { |
203 | *dst = comp(*src, *dst, first); |
204 | dst--; |
205 | src--; |
206 | n -= dst_idx+1; |
207 | } |
208 | |
209 | /* Main chunk */ |
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 | /* Trailing bits */ |
225 | if (last) |
226 | *dst = comp(*src, *dst, last); |
227 | } |
228 | } else { |
229 | /* Different alignment for source and dest */ |
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 | /* Single destination word */ |
236 | if (last) |
237 | first &= last; |
238 | if (shift < 0) { |
239 | /* Single source word */ |
240 | *dst = comp(*src << left, *dst, first); |
241 | } else if (1+(unsigned long)src_idx >= n) { |
242 | /* Single source word */ |
243 | *dst = comp(*src >> right, *dst, first); |
244 | } else { |
245 | /* 2 source words */ |
246 | *dst = comp(*src >> right | *(src-1) << left, |
247 | *dst, first); |
248 | } |
249 | } else { |
250 | /* Multiple destination words */ |
251 | /** We must always remember the last value read, |
252 | because in case SRC and DST overlap bitwise (e.g. |
253 | when moving just one pixel in 1bpp), we always |
254 | collect one full long for DST and that might |
255 | overlap with the current long from SRC. We store |
256 | this value in 'd0'. */ |
257 | unsigned long d0, d1; |
258 | int m; |
259 | |
260 | d0 = *src--; |
261 | /* Leading bits */ |
262 | if (shift < 0) { |
263 | /* Single source word */ |
264 | *dst = comp(d0 << left, *dst, first); |
265 | } else { |
266 | /* 2 source words */ |
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 | /* Main chunk */ |
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 | /* Trailing bits */ |
300 | if (last) { |
301 | if (m <= left) { |
302 | /* Single source word */ |
303 | *dst = comp(d0 >> right, *dst, last); |
304 | } else { |
305 | /* 2 source words */ |
306 | d1 = *src; |
307 | *dst = comp(d0 >> right | d1 << left, |
308 | *dst, last); |
309 | } |
310 | } |
311 | } |
312 | } |
313 | } |
314 | |
315 | void 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 | /* if the beginning of the target area might overlap with the end of |
328 | the source area, be have to copy the area reverse. */ |
329 | if ((dy == sy && dx > sx) || (dy > sy)) { |
330 | dy += height; |
331 | sy += height; |
332 | rev_copy = 1; |
333 | } |
334 | |
335 | /* split the base of the framebuffer into a long-aligned address and |
336 | the index of the first bit */ |
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 | /* add offset of source and target area */ |
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 | |
372 | EXPORT_SYMBOL(sys_copyarea); |
373 | |
374 | MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); |
375 | MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)"); |
376 | MODULE_LICENSE("GPL"); |
377 | |
378 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9