Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1/*
  2 *  Generic fillrect for frame buffers in system RAM with packed pixels of
  3 *  any depth.
  4 *
  5 *  Based almost entirely from cfbfillrect.c (which is based almost entirely
  6 *  on Geert Uytterhoeven's fillrect 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#include <linux/module.h>
 15#include <linux/string.h>
 16#include <linux/fb.h>
 17#include <asm/types.h>
 18#include "fb_draw.h"
 19
 20    /*
 21     *  Aligned pattern fill using 32/64-bit memory accesses
 22     */
 23
 24static void
 25bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
 26		unsigned long pat, unsigned n, int bits)
 27{
 28	unsigned long first, last;
 29
 30	if (!n)
 31		return;
 32
 33	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
 34	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
 35
 36	if (dst_idx+n <= bits) {
 37		/* Single word */
 38		if (last)
 39			first &= last;
 40		*dst = comp(pat, *dst, first);
 41	} else {
 42		/* Multiple destination words */
 43
 44		/* Leading bits */
 45 		if (first!= ~0UL) {
 46			*dst = comp(pat, *dst, first);
 47			dst++;
 48			n -= bits - dst_idx;
 49		}
 50
 51		/* Main chunk */
 52		n /= bits;
 53		while (n >= 8) {
 54			*dst++ = pat;
 55			*dst++ = pat;
 56			*dst++ = pat;
 57			*dst++ = pat;
 58			*dst++ = pat;
 59			*dst++ = pat;
 60			*dst++ = pat;
 61			*dst++ = pat;
 62			n -= 8;
 63		}
 64		while (n--)
 65			*dst++ = pat;
 66		/* Trailing bits */
 67		if (last)
 68			*dst = comp(pat, *dst, last);
 69	}
 70}
 71
 72
 73    /*
 74     *  Unaligned generic pattern fill using 32/64-bit memory accesses
 75     *  The pattern must have been expanded to a full 32/64-bit value
 76     *  Left/right are the appropriate shifts to convert to the pattern to be
 77     *  used for the next 32/64-bit word
 78     */
 79
 80static void
 81bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
 82		  unsigned long pat, int left, int right, unsigned n, int bits)
 83{
 84	unsigned long first, last;
 85
 86	if (!n)
 87		return;
 88
 89	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
 90	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
 91
 92	if (dst_idx+n <= bits) {
 93		/* Single word */
 94		if (last)
 95			first &= last;
 96		*dst = comp(pat, *dst, first);
 97	} else {
 98		/* Multiple destination words */
 99		/* Leading bits */
100		if (first) {
101			*dst = comp(pat, *dst, first);
102			dst++;
103			pat = pat << left | pat >> right;
104			n -= bits - dst_idx;
105		}
106
107		/* Main chunk */
108		n /= bits;
109		while (n >= 4) {
110			*dst++ = pat;
111			pat = pat << left | pat >> right;
112			*dst++ = pat;
113			pat = pat << left | pat >> right;
114			*dst++ = pat;
115			pat = pat << left | pat >> right;
116			*dst++ = pat;
117			pat = pat << left | pat >> right;
118			n -= 4;
119		}
120		while (n--) {
121			*dst++ = pat;
122			pat = pat << left | pat >> right;
123		}
124
125		/* Trailing bits */
126		if (last)
127			*dst = comp(pat, *dst, last);
128	}
129}
130
131    /*
132     *  Aligned pattern invert using 32/64-bit memory accesses
133     */
134static void
135bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
136		    unsigned long pat, unsigned n, int bits)
137{
138	unsigned long val = pat;
139	unsigned long first, last;
140
141	if (!n)
142		return;
143
144	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
145	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
146
147	if (dst_idx+n <= bits) {
148		/* Single word */
149		if (last)
150			first &= last;
151		*dst = comp(*dst ^ val, *dst, first);
152	} else {
153		/* Multiple destination words */
154		/* Leading bits */
155		if (first!=0UL) {
156			*dst = comp(*dst ^ val, *dst, first);
157			dst++;
158			n -= bits - dst_idx;
159		}
160
161		/* Main chunk */
162		n /= bits;
163		while (n >= 8) {
164			*dst++ ^= val;
165			*dst++ ^= val;
166			*dst++ ^= val;
167			*dst++ ^= val;
168			*dst++ ^= val;
169			*dst++ ^= val;
170			*dst++ ^= val;
171			*dst++ ^= val;
172			n -= 8;
173		}
174		while (n--)
175			*dst++ ^= val;
176		/* Trailing bits */
177		if (last)
178			*dst = comp(*dst ^ val, *dst, last);
179	}
180}
181
182
183    /*
184     *  Unaligned generic pattern invert using 32/64-bit memory accesses
185     *  The pattern must have been expanded to a full 32/64-bit value
186     *  Left/right are the appropriate shifts to convert to the pattern to be
187     *  used for the next 32/64-bit word
188     */
189
190static void
191bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
192		      unsigned long pat, int left, int right, unsigned n,
193		      int bits)
194{
195	unsigned long first, last;
196
197	if (!n)
198		return;
199
200	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
201	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
202
203	if (dst_idx+n <= bits) {
204		/* Single word */
205		if (last)
206			first &= last;
207		*dst = comp(*dst ^ pat, *dst, first);
208	} else {
209		/* Multiple destination words */
210
211		/* Leading bits */
212		if (first != 0UL) {
213			*dst = comp(*dst ^ pat, *dst, first);
214			dst++;
215			pat = pat << left | pat >> right;
216			n -= bits - dst_idx;
217		}
218
219		/* Main chunk */
220		n /= bits;
221		while (n >= 4) {
222			*dst++ ^= pat;
223			pat = pat << left | pat >> right;
224			*dst++ ^= pat;
225			pat = pat << left | pat >> right;
226			*dst++ ^= pat;
227			pat = pat << left | pat >> right;
228			*dst++ ^= pat;
229			pat = pat << left | pat >> right;
230			n -= 4;
231		}
232		while (n--) {
233			*dst ^= pat;
234			pat = pat << left | pat >> right;
235		}
236
237		/* Trailing bits */
238		if (last)
239			*dst = comp(*dst ^ pat, *dst, last);
240	}
241}
242
243void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
244{
245	unsigned long pat, pat2, fg;
246	unsigned long width = rect->width, height = rect->height;
247	int bits = BITS_PER_LONG, bytes = bits >> 3;
248	u32 bpp = p->var.bits_per_pixel;
249	unsigned long *dst;
250	int dst_idx, left;
251
252	if (p->state != FBINFO_STATE_RUNNING)
253		return;
254
255	if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
256	    p->fix.visual == FB_VISUAL_DIRECTCOLOR )
257		fg = ((u32 *) (p->pseudo_palette))[rect->color];
258	else
259		fg = rect->color;
260
261	pat = pixel_to_pat( bpp, fg);
262
263	dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
264	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
265	dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
266	/* FIXME For now we support 1-32 bpp only */
267	left = bits % bpp;
268	if (p->fbops->fb_sync)
269		p->fbops->fb_sync(p);
270	if (!left) {
271		void (*fill_op32)(struct fb_info *p, unsigned long *dst,
272				  int dst_idx, unsigned long pat, unsigned n,
273				  int bits) = NULL;
274
275		switch (rect->rop) {
276		case ROP_XOR:
277			fill_op32 = bitfill_aligned_rev;
278			break;
279		case ROP_COPY:
280			fill_op32 = bitfill_aligned;
281			break;
282		default:
283			printk( KERN_ERR "cfb_fillrect(): unknown rop, "
284				"defaulting to ROP_COPY\n");
285			fill_op32 = bitfill_aligned;
286			break;
287		}
288		while (height--) {
289			dst += dst_idx >> (ffs(bits) - 1);
290			dst_idx &= (bits - 1);
291			fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
292			dst_idx += p->fix.line_length*8;
293		}
294	} else {
295		int right, r;
296		void (*fill_op)(struct fb_info *p, unsigned long *dst,
297				int dst_idx, unsigned long pat, int left,
298				int right, unsigned n, int bits) = NULL;
299#ifdef __LITTLE_ENDIAN
300		right = left;
301		left = bpp - right;
302#else
303		right = bpp - left;
304#endif
305		switch (rect->rop) {
306		case ROP_XOR:
307			fill_op = bitfill_unaligned_rev;
308			break;
309		case ROP_COPY:
310			fill_op = bitfill_unaligned;
311			break;
312		default:
313			printk(KERN_ERR "sys_fillrect(): unknown rop, "
314				"defaulting to ROP_COPY\n");
315			fill_op = bitfill_unaligned;
316			break;
317		}
318		while (height--) {
319			dst += dst_idx / bits;
320			dst_idx &= (bits - 1);
321			r = dst_idx % bpp;
322			/* rotate pattern to the correct start position */
323			pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
324			fill_op(p, dst, dst_idx, pat2, left, right,
325				width*bpp, bits);
326			dst_idx += p->fix.line_length*8;
327		}
328	}
329}
330
331EXPORT_SYMBOL(sys_fillrect);
332
333MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
334MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
335MODULE_LICENSE("GPL");