Rev 468 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
468 | giacomo | 1 | /* |
2 | * Generic function for frame buffer with packed pixels of any depth. |
||
3 | * |
||
4 | * Copyright (C) June 1999 James Simmons |
||
5 | * |
||
6 | * This file is subject to the terms and conditions of the GNU General Public |
||
7 | * License. See the file COPYING in the main directory of this archive for |
||
8 | * more details. |
||
9 | * |
||
10 | * NOTES: |
||
11 | * |
||
12 | * This is for cfb packed pixels. Iplan and such are incorporated in the |
||
13 | * drivers that need them. |
||
14 | * |
||
15 | * FIXME |
||
16 | * The code for 24 bit is horrible. It copies byte by byte size instead of |
||
17 | * longs like the other sizes. Needs to be optimized. |
||
18 | * |
||
19 | * Also need to add code to deal with cards endians that are different than |
||
20 | * the native cpu endians. I also need to deal with MSB position in the word. |
||
21 | * |
||
22 | */ |
||
23 | |||
24 | #include <linuxcomp.h> |
||
25 | |||
26 | #include <linux/config.h> |
||
27 | #include <linux/module.h> |
||
28 | #include <linux/kernel.h> |
||
29 | #include <linux/string.h> |
||
30 | #include <linux/fb.h> |
||
31 | #include <linux/slab.h> |
||
32 | #include <asm/types.h> |
||
33 | #include <asm/io.h> |
||
34 | |||
35 | #define LONG_MASK (BITS_PER_LONG - 1) |
||
36 | |||
37 | #if BITS_PER_LONG == 32 |
||
38 | #define FB_WRITEL fb_writel |
||
39 | #define FB_READL fb_readl |
||
40 | #define SHIFT_PER_LONG 5 |
||
41 | #define BYTES_PER_LONG 4 |
||
42 | #else |
||
43 | #define FB_WRITEL fb_writeq |
||
44 | #define FB_READL fb_readq |
||
45 | #define SHIFT_PER_LONG 6 |
||
46 | #define BYTES_PER_LONG 8 |
||
47 | #endif |
||
48 | |||
49 | static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, |
||
50 | int src_idx, unsigned long n) |
||
51 | { |
||
52 | unsigned long first, last; |
||
53 | int shift = dst_idx-src_idx, left, right; |
||
54 | unsigned long d0, d1; |
||
55 | int m; |
||
56 | |||
57 | if (!n) |
||
58 | return; |
||
59 | |||
60 | shift = dst_idx-src_idx; |
||
61 | first = ~0UL >> dst_idx; |
||
62 | last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); |
||
63 | |||
64 | if (!shift) { |
||
65 | // Same alignment for source and dest |
||
66 | |||
67 | if (dst_idx+n <= BITS_PER_LONG) { |
||
68 | // Single word |
||
69 | if (last) |
||
70 | first &= last; |
||
71 | FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst); |
||
72 | } else { |
||
73 | // Multiple destination words |
||
74 | // Leading bits |
||
75 | if (first) { |
||
76 | |||
77 | FB_WRITEL((FB_READL(src) & first) | |
||
78 | (FB_READL(dst) & ~first), dst); |
||
79 | dst++; |
||
80 | src++; |
||
81 | n -= BITS_PER_LONG-dst_idx; |
||
82 | } |
||
83 | |||
84 | // Main chunk |
||
85 | n /= BITS_PER_LONG; |
||
86 | while (n >= 8) { |
||
87 | FB_WRITEL(FB_READL(src++), dst++); |
||
88 | FB_WRITEL(FB_READL(src++), dst++); |
||
89 | FB_WRITEL(FB_READL(src++), dst++); |
||
90 | FB_WRITEL(FB_READL(src++), dst++); |
||
91 | FB_WRITEL(FB_READL(src++), dst++); |
||
92 | FB_WRITEL(FB_READL(src++), dst++); |
||
93 | FB_WRITEL(FB_READL(src++), dst++); |
||
94 | FB_WRITEL(FB_READL(src++), dst++); |
||
95 | n -= 8; |
||
96 | } |
||
97 | while (n--) |
||
98 | FB_WRITEL(FB_READL(src++), dst++); |
||
99 | // Trailing bits |
||
100 | if (last) |
||
101 | FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst); |
||
102 | } |
||
103 | } else { |
||
104 | // Different alignment for source and dest |
||
105 | |||
106 | right = shift & (BITS_PER_LONG-1); |
||
107 | left = -shift & (BITS_PER_LONG-1); |
||
108 | |||
109 | if (dst_idx+n <= BITS_PER_LONG) { |
||
110 | // Single destination word |
||
111 | if (last) |
||
112 | first &= last; |
||
113 | if (shift > 0) { |
||
114 | // Single source word |
||
115 | FB_WRITEL(((FB_READL(src) >> right) & first) | |
||
116 | (FB_READL(dst) & ~first), dst); |
||
117 | } else if (src_idx+n <= BITS_PER_LONG) { |
||
118 | // Single source word |
||
119 | FB_WRITEL(((FB_READL(src) << left) & first) | |
||
120 | (FB_READL(dst) & ~first), dst); |
||
121 | } else { |
||
122 | // 2 source words |
||
123 | d0 = FB_READL(src++); |
||
124 | d1 = FB_READL(src); |
||
125 | FB_WRITEL(((d0<<left | d1>>right) & first) | |
||
126 | (FB_READL(dst) & ~first), dst); |
||
127 | } |
||
128 | } else { |
||
129 | // Multiple destination words |
||
130 | d0 = FB_READL(src++); |
||
131 | // Leading bits |
||
132 | if (shift > 0) { |
||
133 | // Single source word |
||
134 | FB_WRITEL(((d0 >> right) & first) | |
||
135 | (FB_READL(dst) & ~first), dst); |
||
136 | dst++; |
||
137 | n -= BITS_PER_LONG-dst_idx; |
||
138 | } else { |
||
139 | // 2 source words |
||
140 | d1 = FB_READL(src++); |
||
141 | FB_WRITEL(((d0<<left | d1>>right) & first) | |
||
142 | (FB_READL(dst) & ~first), dst); |
||
143 | d0 = d1; |
||
144 | dst++; |
||
145 | n -= BITS_PER_LONG-dst_idx; |
||
146 | } |
||
147 | |||
148 | // Main chunk |
||
149 | m = n % BITS_PER_LONG; |
||
150 | n /= BITS_PER_LONG; |
||
151 | while (n >= 4) { |
||
152 | d1 = FB_READL(src++); |
||
153 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
||
154 | d0 = d1; |
||
155 | d1 = FB_READL(src++); |
||
156 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
||
157 | d0 = d1; |
||
158 | d1 = FB_READL(src++); |
||
159 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
||
160 | d0 = d1; |
||
161 | d1 = FB_READL(src++); |
||
162 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
||
163 | d0 = d1; |
||
164 | n -= 4; |
||
165 | } |
||
166 | while (n--) { |
||
167 | d1 = FB_READL(src++); |
||
168 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
||
169 | d0 = d1; |
||
170 | } |
||
171 | |||
172 | // Trailing bits |
||
173 | if (last) { |
||
174 | if (m <= right) { |
||
175 | // Single source word |
||
176 | FB_WRITEL(((d0 << left) & last) | |
||
177 | (FB_READL(dst) & ~last), |
||
178 | dst); |
||
179 | } else { |
||
180 | // 2 source words |
||
181 | d1 = FB_READL(src); |
||
182 | FB_WRITEL(((d0<<left | d1>>right) & |
||
183 | last) | (FB_READL(dst) & |
||
184 | ~last), dst); |
||
185 | } |
||
186 | } |
||
187 | } |
||
188 | } |
||
189 | } |
||
190 | |||
191 | static void bitcpy_rev(unsigned long *dst, int dst_idx, |
||
192 | const unsigned long *src, int src_idx, unsigned long n) |
||
193 | { |
||
194 | unsigned long first, last; |
||
195 | int shift = dst_idx-src_idx, left, right; |
||
196 | unsigned long d0, d1; |
||
197 | int m; |
||
198 | |||
199 | if (!n) |
||
200 | return; |
||
201 | |||
202 | dst += (n-1)/BITS_PER_LONG; |
||
203 | src += (n-1)/BITS_PER_LONG; |
||
204 | if ((n-1) % BITS_PER_LONG) { |
||
205 | dst_idx += (n-1) % BITS_PER_LONG; |
||
206 | dst += dst_idx >> SHIFT_PER_LONG; |
||
207 | dst_idx &= BITS_PER_LONG-1; |
||
208 | src_idx += (n-1) % BITS_PER_LONG; |
||
209 | src += src_idx >> SHIFT_PER_LONG; |
||
210 | src_idx &= BITS_PER_LONG-1; |
||
211 | } |
||
212 | |||
213 | shift = dst_idx-src_idx; |
||
214 | first = ~0UL << (BITS_PER_LONG-1-dst_idx); |
||
215 | last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG))); |
||
216 | |||
217 | if (!shift) { |
||
218 | // Same alignment for source and dest |
||
219 | |||
220 | if ((unsigned long)dst_idx+1 >= n) { |
||
221 | // Single word |
||
222 | if (last) |
||
223 | first &= last; |
||
224 | FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst); |
||
225 | } else { |
||
226 | // Multiple destination words |
||
227 | // Leading bits |
||
228 | if (first) { |
||
229 | FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst); |
||
230 | dst--; |
||
231 | src--; |
||
232 | n -= dst_idx+1; |
||
233 | } |
||
234 | |||
235 | // Main chunk |
||
236 | n /= BITS_PER_LONG; |
||
237 | while (n >= 8) { |
||
238 | FB_WRITEL(FB_READL(src--), dst--); |
||
239 | FB_WRITEL(FB_READL(src--), dst--); |
||
240 | FB_WRITEL(FB_READL(src--), dst--); |
||
241 | FB_WRITEL(FB_READL(src--), dst--); |
||
242 | FB_WRITEL(FB_READL(src--), dst--); |
||
243 | FB_WRITEL(FB_READL(src--), dst--); |
||
244 | FB_WRITEL(FB_READL(src--), dst--); |
||
245 | FB_WRITEL(FB_READL(src--), dst--); |
||
246 | n -= 8; |
||
247 | } |
||
248 | while (n--) |
||
249 | FB_WRITEL(FB_READL(src--), dst--); |
||
250 | |||
251 | // Trailing bits |
||
252 | if (last) |
||
253 | FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst); |
||
254 | } |
||
255 | } else { |
||
256 | // Different alignment for source and dest |
||
257 | |||
258 | right = shift & (BITS_PER_LONG-1); |
||
259 | left = -shift & (BITS_PER_LONG-1); |
||
260 | |||
261 | if ((unsigned long)dst_idx+1 >= n) { |
||
262 | // Single destination word |
||
263 | if (last) |
||
264 | first &= last; |
||
265 | if (shift < 0) { |
||
266 | // Single source word |
||
267 | FB_WRITEL((FB_READL(src) << left & first) | |
||
268 | (FB_READL(dst) & ~first), dst); |
||
269 | } else if (1+(unsigned long)src_idx >= n) { |
||
270 | // Single source word |
||
271 | FB_WRITEL(((FB_READL(src) >> right) & first) | |
||
272 | (FB_READL(dst) & ~first), dst); |
||
273 | } else { |
||
274 | // 2 source words |
||
275 | d0 = FB_READL(src--); |
||
276 | d1 = FB_READL(src); |
||
277 | FB_WRITEL(((d0>>right | d1<<left) & first) | |
||
278 | (FB_READL(dst) & ~first), dst); |
||
279 | } |
||
280 | } else { |
||
281 | // Multiple destination words |
||
282 | d0 = FB_READL(src--); |
||
283 | // Leading bits |
||
284 | if (shift < 0) { |
||
285 | // Single source word |
||
286 | FB_WRITEL(((d0 << left) & first) | |
||
287 | (FB_READL(dst) & ~first), dst); |
||
288 | dst--; |
||
289 | n -= dst_idx+1; |
||
290 | } else { |
||
291 | // 2 source words |
||
292 | d1 = FB_READL(src--); |
||
293 | FB_WRITEL(((d0>>right | d1<<left) & first) | |
||
294 | (FB_READL(dst) & ~first), dst); |
||
295 | d0 = d1; |
||
296 | dst--; |
||
297 | n -= dst_idx+1; |
||
298 | } |
||
299 | |||
300 | // Main chunk |
||
301 | m = n % BITS_PER_LONG; |
||
302 | n /= BITS_PER_LONG; |
||
303 | while (n >= 4) { |
||
304 | d1 = FB_READL(src--); |
||
305 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
||
306 | d0 = d1; |
||
307 | d1 = FB_READL(src--); |
||
308 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
||
309 | d0 = d1; |
||
310 | d1 = FB_READL(src--); |
||
311 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
||
312 | d0 = d1; |
||
313 | d1 = FB_READL(src--); |
||
314 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
||
315 | d0 = d1; |
||
316 | n -= 4; |
||
317 | } |
||
318 | while (n--) { |
||
319 | d1 = FB_READL(src--); |
||
320 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
||
321 | d0 = d1; |
||
322 | } |
||
323 | |||
324 | // Trailing bits |
||
325 | if (last) { |
||
326 | if (m <= left) { |
||
327 | // Single source word |
||
328 | FB_WRITEL(((d0 >> right) & last) | |
||
329 | (FB_READL(dst) & ~last), |
||
330 | dst); |
||
331 | } else { |
||
332 | // 2 source words |
||
333 | d1 = FB_READL(src); |
||
334 | FB_WRITEL(((d0>>right | d1<<left) & |
||
335 | last) | (FB_READL(dst) & |
||
336 | ~last), dst); |
||
337 | } |
||
338 | } |
||
339 | } |
||
340 | } |
||
341 | } |
||
342 | |||
343 | void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) |
||
344 | { |
||
345 | u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; |
||
346 | u32 height = area->height, width = area->width; |
||
347 | int x2, y2, old_dx, old_dy, vxres, vyres; |
||
348 | unsigned long next_line = p->fix.line_length; |
||
349 | int dst_idx = 0, src_idx = 0, rev_copy = 0; |
||
350 | unsigned long *dst = NULL, *src = NULL; |
||
351 | |||
352 | /* We want rotation but lack hardware to do it for us. */ |
||
353 | if (!p->fbops->fb_rotate && p->var.rotate) { |
||
354 | } |
||
355 | |||
356 | vxres = p->var.xres_virtual; |
||
357 | vyres = p->var.yres_virtual; |
||
358 | |||
359 | if (area->dx > vxres || area->sx > vxres || |
||
360 | area->dy > vyres || area->sy > vyres) |
||
361 | return; |
||
362 | |||
363 | /* clip the destination */ |
||
364 | old_dx = area->dx; |
||
365 | old_dy = area->dy; |
||
366 | |||
367 | /* |
||
368 | * We could use hardware clipping but on many cards you get around |
||
369 | * hardware clipping by writing to framebuffer directly. |
||
370 | */ |
||
371 | x2 = area->dx + area->width; |
||
372 | y2 = area->dy + area->height; |
||
373 | dx = area->dx > 0 ? area->dx : 0; |
||
374 | dy = area->dy > 0 ? area->dy : 0; |
||
375 | x2 = x2 < vxres ? x2 : vxres; |
||
376 | y2 = y2 < vyres ? y2 : vyres; |
||
377 | width = x2 - dx; |
||
378 | height = y2 - dy; |
||
379 | |||
380 | /* update sx1,sy1 */ |
||
381 | sx += (dx - old_dx); |
||
382 | sy += (dy - old_dy); |
||
383 | |||
384 | /* the source must be completely inside the virtual screen */ |
||
385 | if (sx < 0 || sy < 0 || |
||
386 | (sx + width) > vxres || |
||
387 | (sy + height) > vyres) |
||
388 | return; |
||
389 | |||
390 | if ((dy == sy && dx > sx) || |
||
391 | (dy > sy)) { |
||
392 | dy += height; |
||
393 | sy += height; |
||
394 | rev_copy = 1; |
||
395 | } |
||
396 | |||
397 | dst = src = (unsigned long *)((unsigned long)p->screen_base & |
||
398 | ~(BYTES_PER_LONG-1)); |
||
399 | dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1); |
||
400 | dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel; |
||
401 | src_idx += sy*next_line*8 + sx*p->var.bits_per_pixel; |
||
402 | |||
403 | if (p->fbops->fb_sync) |
||
404 | p->fbops->fb_sync(p); |
||
405 | if (rev_copy) { |
||
406 | while (height--) { |
||
407 | dst_idx -= next_line*8; |
||
408 | src_idx -= next_line*8; |
||
409 | dst += dst_idx >> SHIFT_PER_LONG; |
||
410 | dst_idx &= (BYTES_PER_LONG-1); |
||
411 | src += src_idx >> SHIFT_PER_LONG; |
||
412 | src_idx &= (BYTES_PER_LONG-1); |
||
413 | bitcpy_rev(dst, dst_idx, src, src_idx, |
||
414 | width*p->var.bits_per_pixel); |
||
415 | } |
||
416 | } else { |
||
417 | while (height--) { |
||
418 | dst += dst_idx >> SHIFT_PER_LONG; |
||
419 | dst_idx &= (BYTES_PER_LONG-1); |
||
420 | src += src_idx >> SHIFT_PER_LONG; |
||
421 | src_idx &= (BYTES_PER_LONG-1); |
||
422 | bitcpy(dst, dst_idx, src, src_idx, |
||
423 | width*p->var.bits_per_pixel); |
||
424 | dst_idx += next_line*8; |
||
425 | src_idx += next_line*8; |
||
426 | } |
||
427 | } |
||
428 | } |
||
429 | |||
430 | EXPORT_SYMBOL(cfb_copyarea); |
||
431 | |||
432 | MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); |
||
433 | MODULE_DESCRIPTION("Generic software accelerated copyarea"); |
||
434 | MODULE_LICENSE("GPL"); |
||
435 |