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