0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/string.h>
0018 #include <linux/fb.h>
0019 #include <asm/types.h>
0020 #include <asm/io.h>
0021 #include "fb_draw.h"
0022
0023
0024
0025
0026
0027 static void
0028 bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
0029 const unsigned long *src, unsigned src_idx, int bits, unsigned n)
0030 {
0031 unsigned long first, last;
0032 int const shift = dst_idx-src_idx;
0033 int left, right;
0034
0035 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0036 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0037
0038 if (!shift) {
0039
0040 if (dst_idx+n <= bits) {
0041
0042 if (last)
0043 first &= last;
0044 *dst = comp(*src, *dst, first);
0045 } else {
0046
0047
0048 if (first != ~0UL) {
0049 *dst = comp(*src, *dst, first);
0050 dst++;
0051 src++;
0052 n -= bits - dst_idx;
0053 }
0054
0055
0056 n /= bits;
0057 while (n >= 8) {
0058 *dst++ = *src++;
0059 *dst++ = *src++;
0060 *dst++ = *src++;
0061 *dst++ = *src++;
0062 *dst++ = *src++;
0063 *dst++ = *src++;
0064 *dst++ = *src++;
0065 *dst++ = *src++;
0066 n -= 8;
0067 }
0068 while (n--)
0069 *dst++ = *src++;
0070
0071
0072 if (last)
0073 *dst = comp(*src, *dst, last);
0074 }
0075 } else {
0076 unsigned long d0, d1;
0077 int m;
0078
0079
0080 right = shift & (bits - 1);
0081 left = -shift & (bits - 1);
0082
0083 if (dst_idx+n <= bits) {
0084
0085 if (last)
0086 first &= last;
0087 if (shift > 0) {
0088
0089 *dst = comp(*src << left, *dst, first);
0090 } else if (src_idx+n <= bits) {
0091
0092 *dst = comp(*src >> right, *dst, first);
0093 } else {
0094
0095 d0 = *src++;
0096 d1 = *src;
0097 *dst = comp(d0 >> right | d1 << left, *dst,
0098 first);
0099 }
0100 } else {
0101
0102
0103
0104
0105
0106
0107
0108 d0 = *src++;
0109
0110 if (shift > 0) {
0111
0112 *dst = comp(d0 << left, *dst, first);
0113 dst++;
0114 n -= bits - dst_idx;
0115 } else {
0116
0117 d1 = *src++;
0118 *dst = comp(d0 >> right | d1 << left, *dst,
0119 first);
0120 d0 = d1;
0121 dst++;
0122 n -= bits - dst_idx;
0123 }
0124
0125
0126 m = n % bits;
0127 n /= bits;
0128 while (n >= 4) {
0129 d1 = *src++;
0130 *dst++ = d0 >> right | d1 << left;
0131 d0 = d1;
0132 d1 = *src++;
0133 *dst++ = d0 >> right | d1 << left;
0134 d0 = d1;
0135 d1 = *src++;
0136 *dst++ = d0 >> right | d1 << left;
0137 d0 = d1;
0138 d1 = *src++;
0139 *dst++ = d0 >> right | d1 << left;
0140 d0 = d1;
0141 n -= 4;
0142 }
0143 while (n--) {
0144 d1 = *src++;
0145 *dst++ = d0 >> right | d1 << left;
0146 d0 = d1;
0147 }
0148
0149
0150 if (m) {
0151 if (m <= bits - right) {
0152
0153 d0 >>= right;
0154 } else {
0155
0156 d1 = *src;
0157 d0 = d0 >> right | d1 << left;
0158 }
0159 *dst = comp(d0, *dst, last);
0160 }
0161 }
0162 }
0163 }
0164
0165
0166
0167
0168
0169 static void
0170 bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
0171 const unsigned long *src, unsigned src_idx, unsigned bits,
0172 unsigned n)
0173 {
0174 unsigned long first, last;
0175 int shift;
0176
0177 dst += (dst_idx + n - 1) / bits;
0178 src += (src_idx + n - 1) / bits;
0179 dst_idx = (dst_idx + n - 1) % bits;
0180 src_idx = (src_idx + n - 1) % bits;
0181
0182 shift = dst_idx-src_idx;
0183
0184 first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
0185 last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
0186
0187 if (!shift) {
0188
0189 if ((unsigned long)dst_idx+1 >= n) {
0190
0191 if (first)
0192 last &= first;
0193 *dst = comp(*src, *dst, last);
0194 } else {
0195
0196
0197
0198 if (first) {
0199 *dst = comp(*src, *dst, first);
0200 dst--;
0201 src--;
0202 n -= dst_idx+1;
0203 }
0204
0205
0206 n /= bits;
0207 while (n >= 8) {
0208 *dst-- = *src--;
0209 *dst-- = *src--;
0210 *dst-- = *src--;
0211 *dst-- = *src--;
0212 *dst-- = *src--;
0213 *dst-- = *src--;
0214 *dst-- = *src--;
0215 *dst-- = *src--;
0216 n -= 8;
0217 }
0218 while (n--)
0219 *dst-- = *src--;
0220
0221 if (last != -1UL)
0222 *dst = comp(*src, *dst, last);
0223 }
0224 } else {
0225
0226
0227 int const left = shift & (bits-1);
0228 int const right = -shift & (bits-1);
0229
0230 if ((unsigned long)dst_idx+1 >= n) {
0231
0232 if (first)
0233 last &= first;
0234 if (shift < 0) {
0235
0236 *dst = comp(*src >> right, *dst, last);
0237 } else if (1+(unsigned long)src_idx >= n) {
0238
0239 *dst = comp(*src << left, *dst, last);
0240 } else {
0241
0242 *dst = comp(*src << left | *(src-1) >> right,
0243 *dst, last);
0244 }
0245 } else {
0246
0247
0248
0249
0250
0251
0252
0253 unsigned long d0, d1;
0254 int m;
0255
0256 d0 = *src--;
0257
0258 if (shift < 0) {
0259
0260 d1 = d0;
0261 d0 >>= right;
0262 } else {
0263
0264 d1 = *src--;
0265 d0 = d0 << left | d1 >> right;
0266 }
0267 if (!first)
0268 *dst = d0;
0269 else
0270 *dst = comp(d0, *dst, first);
0271 d0 = d1;
0272 dst--;
0273 n -= dst_idx+1;
0274
0275
0276 m = n % bits;
0277 n /= bits;
0278 while (n >= 4) {
0279 d1 = *src--;
0280 *dst-- = d0 << left | d1 >> right;
0281 d0 = d1;
0282 d1 = *src--;
0283 *dst-- = d0 << left | d1 >> right;
0284 d0 = d1;
0285 d1 = *src--;
0286 *dst-- = d0 << left | d1 >> right;
0287 d0 = d1;
0288 d1 = *src--;
0289 *dst-- = d0 << left | d1 >> right;
0290 d0 = d1;
0291 n -= 4;
0292 }
0293 while (n--) {
0294 d1 = *src--;
0295 *dst-- = d0 << left | d1 >> right;
0296 d0 = d1;
0297 }
0298
0299
0300 if (m) {
0301 if (m <= bits - left) {
0302
0303 d0 <<= left;
0304 } else {
0305
0306 d1 = *src;
0307 d0 = d0 << left | d1 >> right;
0308 }
0309 *dst = comp(d0, *dst, last);
0310 }
0311 }
0312 }
0313 }
0314
0315 void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
0316 {
0317 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
0318 u32 height = area->height, width = area->width;
0319 unsigned long const bits_per_line = p->fix.line_length*8u;
0320 unsigned long *base = NULL;
0321 int bits = BITS_PER_LONG, bytes = bits >> 3;
0322 unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
0323
0324 if (p->state != FBINFO_STATE_RUNNING)
0325 return;
0326
0327
0328
0329 if ((dy == sy && dx > sx) || (dy > sy)) {
0330 dy += height;
0331 sy += height;
0332 rev_copy = 1;
0333 }
0334
0335
0336
0337 base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
0338 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
0339
0340 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
0341 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
0342
0343 if (p->fbops->fb_sync)
0344 p->fbops->fb_sync(p);
0345
0346 if (rev_copy) {
0347 while (height--) {
0348 dst_idx -= bits_per_line;
0349 src_idx -= bits_per_line;
0350 bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
0351 base + (src_idx / bits), src_idx % bits, bits,
0352 width*p->var.bits_per_pixel);
0353 }
0354 } else {
0355 while (height--) {
0356 bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
0357 base + (src_idx / bits), src_idx % bits, bits,
0358 width*p->var.bits_per_pixel);
0359 dst_idx += bits_per_line;
0360 src_idx += bits_per_line;
0361 }
0362 }
0363 }
0364
0365 EXPORT_SYMBOL(sys_copyarea);
0366
0367 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
0368 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
0369 MODULE_LICENSE("GPL");
0370