brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 75e7001 Raw
374 lines · c
1/*2 *  Generic Bit Block Transfer for frame buffers located in system RAM with3 *  packed pixels of any depth.4 *5 *  Based almost entirely from cfbcopyarea.c (which is based almost entirely6 *  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 Public11 *  License.  See the file COPYING in the main directory of this archive for12 *  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 algorithm25     */26 27static void28bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,29	const unsigned long *src, unsigned 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 << left, *dst, first);90			} else if (src_idx+n <= bits) {91				/* Single source word */92				*dst = comp(*src >> right, *dst, first);93			} else {94				/* 2 source words */95				d0 = *src++;96				d1 = *src;97				*dst = comp(d0 >> right | d1 << left, *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 always105			    collect one full long for DST and that might106			    overlap with the current long from SRC. We store107			    this value in 'd0'. */108			d0 = *src++;109			/* Leading bits */110			if (shift > 0) {111				/* Single source word */112				*dst = comp(d0 << left, *dst, first);113				dst++;114				n -= bits - dst_idx;115			} else {116				/* 2 source words */117				d1 = *src++;118				*dst = comp(d0 >> right | d1 << left, *dst,119					    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 >> right | d1 << left;131				d0 = d1;132				d1 = *src++;133				*dst++ = d0 >> right | d1 << left;134				d0 = d1;135				d1 = *src++;136				*dst++ = d0 >> right | d1 << left;137				d0 = d1;138				d1 = *src++;139				*dst++ = d0 >> right | d1 << left;140				d0 = d1;141				n -= 4;142			}143			while (n--) {144				d1 = *src++;145				*dst++ = d0 >> right | d1 << left;146				d0 = d1;147			}148 149			/* Trailing bits */150			if (m) {151				if (m <= bits - right) {152					/* Single source word */153					d0 >>= right;154				} else {155					/* 2 source words */156 					d1 = *src;157					d0 = d0 >> right | d1 << left;158				}159				*dst = comp(d0, *dst, last);160			}161		}162	}163}164 165    /*166     *  Generic bitwise copy algorithm, operating backward167     */168 169static void170bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,171	   const unsigned long *src, unsigned src_idx, unsigned bits,172	   unsigned n)173{174	unsigned long first, last;175	int shift;176 177	dst += (dst_idx + n - 1) / bits;178	src += (src_idx + n - 1) / bits;179	dst_idx = (dst_idx + n - 1) % bits;180	src_idx = (src_idx + n - 1) % bits;181 182	shift = dst_idx-src_idx;183 184	first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);185	last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);186 187	if (!shift) {188		/* Same alignment for source and dest */189		if ((unsigned long)dst_idx+1 >= n) {190			/* Single word */191			if (first)192				last &= first;193			*dst = comp(*src, *dst, last);194		} else {195			/* Multiple destination words */196 197			/* Leading bits */198			if (first) {199				*dst = comp(*src, *dst, first);200				dst--;201				src--;202				n -= dst_idx+1;203			}204 205			/* Main chunk */206			n /= bits;207			while (n >= 8) {208				*dst-- = *src--;209				*dst-- = *src--;210				*dst-- = *src--;211				*dst-- = *src--;212				*dst-- = *src--;213				*dst-- = *src--;214				*dst-- = *src--;215				*dst-- = *src--;216				n -= 8;217			}218			while (n--)219				*dst-- = *src--;220			/* Trailing bits */221			if (last != -1UL)222				*dst = comp(*src, *dst, last);223		}224	} else {225		/* Different alignment for source and dest */226 227		int const left = shift & (bits-1);228		int const right = -shift & (bits-1);229 230		if ((unsigned long)dst_idx+1 >= n) {231			/* Single destination word */232			if (first)233				last &= first;234			if (shift < 0) {235				/* Single source word */236				*dst = comp(*src >> right, *dst, last);237			} else if (1+(unsigned long)src_idx >= n) {238				/* Single source word */239				*dst = comp(*src << left, *dst, last);240			} else {241				/* 2 source words */242				*dst = comp(*src << left | *(src-1) >> right,243					    *dst, last);244			}245		} else {246			/* Multiple destination words */247			/** We must always remember the last value read,248			    because in case SRC and DST overlap bitwise (e.g.249			    when moving just one pixel in 1bpp), we always250			    collect one full long for DST and that might251			    overlap with the current long from SRC. We store252			    this value in 'd0'. */253			unsigned long d0, d1;254			int m;255 256			d0 = *src--;257			/* Leading bits */258			if (shift < 0) {259				/* Single source word */260				d1 = d0;261				d0 >>= right;262			} else {263				/* 2 source words */264				d1 = *src--;265				d0 = d0 << left | d1 >> right;266			}267			if (!first)268				*dst = d0;269			else270				*dst = comp(d0, *dst, first);271			d0 = d1;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 << left | d1 >> right;281				d0 = d1;282				d1 = *src--;283				*dst-- = d0 << left | d1 >> right;284				d0 = d1;285				d1 = *src--;286				*dst-- = d0 << left | d1 >> right;287				d0 = d1;288				d1 = *src--;289				*dst-- = d0 << left | d1 >> right;290				d0 = d1;291				n -= 4;292			}293			while (n--) {294				d1 = *src--;295				*dst-- = d0 << left | d1 >> right;296				d0 = d1;297			}298 299			/* Trailing bits */300			if (m) {301				if (m <= bits - left) {302					/* Single source word */303					d0 <<= left;304				} else {305					/* 2 source words */306					d1 = *src;307					d0 = d0 << left | d1 >> right;308				}309				*dst = comp(d0, *dst, last);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 int const bits_per_line = p->fix.line_length * 8u;320	unsigned long *base = NULL;321	int bits = BITS_PER_LONG, bytes = bits >> 3;322	unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;323 324	if (p->state != FBINFO_STATE_RUNNING)325		return;326 327	if (!(p->flags & FBINFO_VIRTFB))328		fb_warn_once(p, "Framebuffer is not in virtual address space.");329 330	/* if the beginning of the target area might overlap with the end of331	the source area, be have to copy the area reverse. */332	if ((dy == sy && dx > sx) || (dy > sy)) {333		dy += height;334		sy += height;335		rev_copy = 1;336	}337 338	/* split the base of the framebuffer into a long-aligned address and339	   the index of the first bit */340	base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));341	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));342	/* add offset of source and target area */343	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;344	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;345 346	if (p->fbops->fb_sync)347		p->fbops->fb_sync(p);348 349	if (rev_copy) {350		while (height--) {351			dst_idx -= bits_per_line;352			src_idx -= bits_per_line;353			bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,354				base + (src_idx / bits), src_idx % bits, bits,355				width*p->var.bits_per_pixel);356		}357	} else {358		while (height--) {359			bitcpy(p, base + (dst_idx / bits), dst_idx % bits,360				base + (src_idx / bits), src_idx % bits, bits,361				width*p->var.bits_per_pixel);362			dst_idx += bits_per_line;363			src_idx += bits_per_line;364		}365	}366}367 368EXPORT_SYMBOL(sys_copyarea);369 370MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");371MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");372MODULE_LICENSE("GPL");373 374