Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sysfillrect.c
Go to the documentation of this file.
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 <[email protected]>
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 
24 static void
25 bitfill_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 
80 static void
81 bitfill_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  */
134 static void
135 bitfill_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 
190 static void
191 bitfill_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 
243 void 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 
332 
333 MODULE_AUTHOR("Antonino Daplas <[email protected]>");
334 MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
335 MODULE_LICENSE("GPL");