1 /*
2  *  linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for
3  *				      interleaved bitplanes à la Atari (2
4  *				      planes, 2 bytes interleave)
5  *
6  *	Created 5 Apr 1997 by Geert Uytterhoeven
7  *
8  *  This file is subject to the terms and conditions of the GNU General Public
9  *  License.  See the file COPYING in the main directory of this archive for
10  *  more details.
11  */
12 
13 #include <linux/module.h>
14 #include <linux/string.h>
15 #include <linux/fb.h>
16 
17 #include <asm/setup.h>
18 
19 #include "atafb.h"
20 
21 #define BPL	2
22 #include "atafb_utils.h"
23 
24 void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line,
25 			     int sy, int sx, int dy, int dx,
26 			     int height, int width)
27 {
28 	/*  bmove() has to distinguish two major cases: If both, source and
29 	 *  destination, start at even addresses or both are at odd
30 	 *  addresses, just the first odd and last even column (if present)
31 	 *  require special treatment (memmove_col()). The rest between
32 	 *  then can be copied by normal operations, because all adjacent
33 	 *  bytes are affected and are to be stored in the same order.
34 	 *    The pathological case is when the move should go from an odd
35 	 *  address to an even or vice versa. Since the bytes in the plane
36 	 *  words must be assembled in new order, it seems wisest to make
37 	 *  all movements by memmove_col().
38 	 */
39 
40 	u8 *src, *dst;
41 	u32 *s, *d;
42 	int w, l , i, j;
43 	u_int colsize;
44 	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
45 
46 	colsize = height;
47 	if (!((sx ^ dx) & 15)) {
48 		/* odd->odd or even->even */
49 
50 		if (upwards) {
51 			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
52 			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
53 			if (sx & 15) {
54 				memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
55 				src += BPL * 2;
56 				dst += BPL * 2;
57 				width -= 8;
58 			}
59 			w = width >> 4;
60 			if (w) {
61 				s = (u32 *)src;
62 				d = (u32 *)dst;
63 				w *= BPL / 2;
64 				l = next_line - w * 4;
65 				for (j = height; j > 0; j--) {
66 					for (i = w; i > 0; i--)
67 						*d++ = *s++;
68 					s = (u32 *)((u8 *)s + l);
69 					d = (u32 *)((u8 *)d + l);
70 				}
71 			}
72 			if (width & 15)
73 				memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
74 					      0xff00ff00, height, next_line - BPL * 2);
75 		} else {
76 			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
77 			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
78 
79 			if ((sx + width) & 15) {
80 				src -= BPL * 2;
81 				dst -= BPL * 2;
82 				memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
83 				width -= 8;
84 			}
85 			w = width >> 4;
86 			if (w) {
87 				s = (u32 *)src;
88 				d = (u32 *)dst;
89 				w *= BPL / 2;
90 				l = next_line - w * 4;
91 				for (j = height; j > 0; j--) {
92 					for (i = w; i > 0; i--)
93 						*--d = *--s;
94 					s = (u32 *)((u8 *)s - l);
95 					d = (u32 *)((u8 *)d - l);
96 				}
97 			}
98 			if (sx & 15)
99 				memmove32_col(dst - (width - 16) / (8 / BPL),
100 					      src - (width - 16) / (8 / BPL),
101 					      0xff00ff, colsize, -next_line - BPL * 2);
102 		}
103 	} else {
104 		/* odd->even or even->odd */
105 		if (upwards) {
106 			u32 *src32, *dst32;
107 			u32 pval[4], v, v1, mask;
108 			int i, j, w, f;
109 
110 			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
111 			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
112 
113 			mask = 0xff00ff00;
114 			f = 0;
115 			w = width;
116 			if (sx & 15) {
117 				f = 1;
118 				w += 8;
119 			}
120 			if ((sx + width) & 15)
121 				f |= 2;
122 			w >>= 4;
123 			for (i = height; i; i--) {
124 				src32 = (u32 *)src;
125 				dst32 = (u32 *)dst;
126 
127 				if (f & 1) {
128 					pval[0] = (*src32++ << 8) & mask;
129 				} else {
130 					pval[0] = dst32[0] & mask;
131 				}
132 
133 				for (j = w; j > 0; j--) {
134 					v = *src32++;
135 					v1 = v & mask;
136 					*dst32++ = pval[0] | (v1 >> 8);
137 					pval[0] = (v ^ v1) << 8;
138 				}
139 
140 				if (f & 2) {
141 					dst32[0] = (dst32[0] & mask) | pval[0];
142 				}
143 
144 				src += next_line;
145 				dst += next_line;
146 			}
147 		} else {
148 			u32 *src32, *dst32;
149 			u32 pval[4], v, v1, mask;
150 			int i, j, w, f;
151 
152 			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
153 			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
154 
155 			mask = 0xff00ff;
156 			f = 0;
157 			w = width;
158 			if ((dx + width) & 15)
159 				f = 1;
160 			if (sx & 15) {
161 				f |= 2;
162 				w += 8;
163 			}
164 			w >>= 4;
165 			for (i = height; i; i--) {
166 				src32 = (u32 *)src;
167 				dst32 = (u32 *)dst;
168 
169 				if (f & 1) {
170 					pval[0] = dst32[-1] & mask;
171 				} else {
172 					pval[0] = (*--src32 >> 8) & mask;
173 				}
174 
175 				for (j = w; j > 0; j--) {
176 					v = *--src32;
177 					v1 = v & mask;
178 					*--dst32 = pval[0] | (v1 << 8);
179 					pval[0] = (v ^ v1) >> 8;
180 				}
181 
182 				if (!(f & 2)) {
183 					dst32[-1] = (dst32[-1] & mask) | pval[0];
184 				}
185 
186 				src -= next_line;
187 				dst -= next_line;
188 			}
189 		}
190 	}
191 }
192 
193 void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
194                              int sy, int sx, int height, int width)
195 {
196 	u32 *dest;
197 	int rows, i;
198 	u32 cval[4];
199 
200 	dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
201 	if (sx & 15) {
202 		u8 *dest8 = (u8 *)dest + 1;
203 
204 		expand8_col2mask(color, cval);
205 
206 		for (i = height; i; i--) {
207 			fill8_col(dest8, cval);
208 			dest8 += next_line;
209 		}
210 		dest += BPL / 2;
211 		width -= 8;
212 	}
213 
214 	expand16_col2mask(color, cval);
215 	rows = width >> 4;
216 	if (rows) {
217 		u32 *d = dest;
218 		u32 off = next_line - rows * BPL * 2;
219 		for (i = height; i; i--) {
220 			d = fill16_col(d, rows, cval);
221 			d = (u32 *)((long)d + off);
222 		}
223 		dest += rows * BPL / 2;
224 		width &= 15;
225 	}
226 
227 	if (width) {
228 		u8 *dest8 = (u8 *)dest;
229 
230 		expand8_col2mask(color, cval);
231 
232 		for (i = height; i; i--) {
233 			fill8_col(dest8, cval);
234 			dest8 += next_line;
235 		}
236 	}
237 }
238 
239 void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
240                              int dy, int dx, u32 width,
241                              const u8 *data, u32 bgcolor, u32 fgcolor)
242 {
243 	u32 *dest;
244 	const u16 *data16;
245 	int rows;
246 	u32 fgm[4], bgm[4], m;
247 
248 	dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
249 	if (dx & 15) {
250 		fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
251 		dest += BPL / 2;
252 		width -= 8;
253 	}
254 
255 	if (width >= 16) {
256 		data16 = (const u16 *)data;
257 		expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
258 
259 		for (rows = width / 16; rows; rows--) {
260 			u16 d = *data16++;
261 			m = d | ((u32)d << 16);
262 			*dest++ = (m & fgm[0]) ^ bgm[0];
263 		}
264 
265 		data = (const u8 *)data16;
266 		width &= 15;
267 	}
268 
269 	if (width)
270 		fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
271 }
272 
273 #ifdef MODULE
274 MODULE_LICENSE("GPL");
275 
276 int init_module(void)
277 {
278 	return 0;
279 }
280 
281 void cleanup_module(void)
282 {
283 }
284 #endif /* MODULE */
285 
286 
287     /*
288      *  Visible symbols for modules
289      */
290 
291 EXPORT_SYMBOL(atafb_iplan2p2_copyarea);
292 EXPORT_SYMBOL(atafb_iplan2p2_fillrect);
293 EXPORT_SYMBOL(atafb_iplan2p2_linefill);
294