Merge branch 'topic/rawmidi-fix' into for-linus
[linux-2.6] / drivers / video / c2p_iplan2.c
1 /*
2  *  Fast C2P (Chunky-to-Planar) Conversion
3  *
4  *  Copyright (C) 2003-2008 Geert Uytterhoeven
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
8  *  for more details.
9  */
10
11 #include <linux/module.h>
12 #include <linux/string.h>
13
14 #include <asm/unaligned.h>
15
16 #include "c2p.h"
17 #include "c2p_core.h"
18
19
20     /*
21      *  Perform a full C2P step on 16 8-bit pixels, stored in 4 32-bit words
22      *  containing
23      *    - 16 8-bit chunky pixels on input
24      *    - permutated planar data (2 planes per 32-bit word) on output
25      */
26
27 static void c2p_16x8(u32 d[4])
28 {
29         transp4(d, 8, 2);
30         transp4(d, 1, 2);
31         transp4x(d, 16, 2);
32         transp4x(d, 2, 2);
33         transp4(d, 4, 1);
34 }
35
36
37     /*
38      *  Array containing the permutation indices of the planar data after c2p
39      */
40
41 static const int perm_c2p_16x8[4] = { 1, 3, 0, 2 };
42
43
44     /*
45      *  Store a full block of iplan2 data after c2p conversion
46      */
47
48 static inline void store_iplan2(void *dst, u32 bpp, u32 d[4])
49 {
50         int i;
51
52         for (i = 0; i < bpp/2; i++, dst += 4)
53                 put_unaligned_be32(d[perm_c2p_16x8[i]], dst);
54 }
55
56
57     /*
58      *  Store a partial block of iplan2 data after c2p conversion
59      */
60
61 static inline void store_iplan2_masked(void *dst, u32 bpp, u32 d[4], u32 mask)
62 {
63         int i;
64
65         for (i = 0; i < bpp/2; i++, dst += 4)
66                 put_unaligned_be32(comp(d[perm_c2p_16x8[i]],
67                                         get_unaligned_be32(dst), mask),
68                                    dst);
69 }
70
71
72     /*
73      *  c2p_iplan2 - Copy 8-bit chunky image data to an interleaved planar
74      *  frame buffer with 2 bytes of interleave
75      *  @dst: Starting address of the planar frame buffer
76      *  @dx: Horizontal destination offset (in pixels)
77      *  @dy: Vertical destination offset (in pixels)
78      *  @width: Image width (in pixels)
79      *  @height: Image height (in pixels)
80      *  @dst_nextline: Frame buffer offset to the next line (in bytes)
81      *  @src_nextline: Image offset to the next line (in bytes)
82      *  @bpp: Bits per pixel of the planar frame buffer (2, 4, or 8)
83      */
84
85 void c2p_iplan2(void *dst, const void *src, u32 dx, u32 dy, u32 width,
86                 u32 height, u32 dst_nextline, u32 src_nextline, u32 bpp)
87 {
88         union {
89                 u8 pixels[16];
90                 u32 words[4];
91         } d;
92         u32 dst_idx, first, last, w;
93         const u8 *c;
94         void *p;
95
96         dst += dy*dst_nextline+(dx & ~15)*bpp;
97         dst_idx = dx % 16;
98         first = 0xffffU >> dst_idx;
99         first |= first << 16;
100         last = 0xffffU ^ (0xffffU >> ((dst_idx+width) % 16));
101         last |= last << 16;
102         while (height--) {
103                 c = src;
104                 p = dst;
105                 w = width;
106                 if (dst_idx+width <= 16) {
107                         /* Single destination word */
108                         first &= last;
109                         memset(d.pixels, 0, sizeof(d));
110                         memcpy(d.pixels+dst_idx, c, width);
111                         c += width;
112                         c2p_16x8(d.words);
113                         store_iplan2_masked(p, bpp, d.words, first);
114                         p += bpp*2;
115                 } else {
116                         /* Multiple destination words */
117                         w = width;
118                         /* Leading bits */
119                         if (dst_idx) {
120                                 w = 16 - dst_idx;
121                                 memset(d.pixels, 0, dst_idx);
122                                 memcpy(d.pixels+dst_idx, c, w);
123                                 c += w;
124                                 c2p_16x8(d.words);
125                                 store_iplan2_masked(p, bpp, d.words, first);
126                                 p += bpp*2;
127                                 w = width-w;
128                         }
129                         /* Main chunk */
130                         while (w >= 16) {
131                                 memcpy(d.pixels, c, 16);
132                                 c += 16;
133                                 c2p_16x8(d.words);
134                                 store_iplan2(p, bpp, d.words);
135                                 p += bpp*2;
136                                 w -= 16;
137                         }
138                         /* Trailing bits */
139                         w %= 16;
140                         if (w > 0) {
141                                 memcpy(d.pixels, c, w);
142                                 memset(d.pixels+w, 0, 16-w);
143                                 c2p_16x8(d.words);
144                                 store_iplan2_masked(p, bpp, d.words, last);
145                         }
146                 }
147                 src += src_nextline;
148                 dst += dst_nextline;
149         }
150 }
151 EXPORT_SYMBOL_GPL(c2p_iplan2);
152
153 MODULE_LICENSE("GPL");