1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/tty.h>
15#include <linux/console.h>
16#include <linux/string.h>
17#include <linux/fb.h>
18
19#include <asm/byteorder.h>
20
21#ifdef __mc68000__
22#include <asm/setup.h>
23#endif
24
25#include <video/fbcon.h>
26#include <video/fbcon-iplan2p2.h>
27
28
29
30
31
32
33
34
35#define INC_2P(p) do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
36#define DEC_2P(p) do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
37
38
39
40
41
42
43static const u8 color_2p[] = { 0, 0, 0, 1, 0, 1, 1, 1, 2, 2, 2, 3, 2, 3, 3, 3 };
44#define COLOR_2P(c) color_2p[c]
45
46
47static inline void movepw(u8 *d, u16 val)
48{
49#if defined __mc68000__ && !defined CPU_M68060_ONLY
50 asm volatile ("movepw %1,%0@(0)" : : "a" (d), "d" (val));
51#else
52 d[0] = (val >> 16) & 0xff;
53 d[2] = val & 0xff;
54#endif
55}
56
57
58
59
60
61
62
63
64
65
66static __inline__ void memclear_2p_col(void *d, size_t h, u16 val, int bpr)
67{
68 u8 *dd = d;
69 do {
70 movepw(dd, val);
71 dd += bpr;
72 } while (--h);
73}
74
75
76
77
78
79
80
81
82
83
84static __inline__ void memset_even_2p(void *d, size_t count, u32 val)
85{
86 u32 *dd = d;
87
88 count /= 4;
89 while (count--)
90 *dd++ = val;
91}
92
93
94
95static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
96{
97 u8 *dd = d, *ss = s;
98
99 while (h--) {
100 dd[0] = ss[0];
101 dd[2] = ss[2];
102 dd += bpr;
103 ss += bpr;
104 }
105}
106
107
108
109
110static const u16 two2byte[] = {
111 0x0000, 0xff00, 0x00ff, 0xffff
112};
113
114static __inline__ u16 expand2w(u8 c)
115{
116 return two2byte[c];
117}
118
119
120
121
122
123
124static const u32 two2word[] = {
125#ifndef __LITTLE_ENDIAN
126 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
127#else
128 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
129#endif
130};
131
132static __inline__ u32 expand2l(u8 c)
133{
134 return two2word[c];
135}
136
137
138
139
140static __inline__ u16 dup2w(u8 c)
141{
142 u16 rv;
143
144 rv = c;
145 rv |= c << 8;
146 return rv;
147}
148
149
150void fbcon_iplan2p2_setup(struct display *p)
151{
152 p->next_line = p->var.xres_virtual>>2;
153 p->next_plane = 2;
154}
155
156void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
157 int height, int width)
158{
159
160
161
162
163
164
165
166
167
168
169
170
171 if (sx == 0 && dx == 0 && width * 2 == p->next_line) {
172
173
174
175 fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
176 p->screen_base + sy * p->next_line * fontheight(p),
177 p->next_line * height * fontheight(p));
178 } else {
179 int rows, cols;
180 u8 *src;
181 u8 *dst;
182 int bytes = p->next_line;
183 int linesize;
184 u_int colsize;
185 u_int upwards = (dy < sy) || (dy == sy && dx < sx);
186
187 if (fontheightlog(p)) {
188 linesize = bytes << fontheightlog(p);
189 colsize = height << fontheightlog(p);
190 } else {
191 linesize = bytes * fontheight(p);
192 colsize = height * fontheight(p);
193 }
194 if ((sx & 1) == (dx & 1)) {
195
196 if (upwards) {
197 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
198 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
199 if (sx & 1) {
200 memmove_2p_col(dst, src, colsize, bytes);
201 src += 3;
202 dst += 3;
203 --width;
204 }
205 if (width > 1) {
206 for (rows = colsize; rows > 0; --rows) {
207 fb_memmove(dst, src, (width>>1)*4);
208 src += bytes;
209 dst += bytes;
210 }
211 }
212 if (width & 1) {
213 src -= colsize * bytes;
214 dst -= colsize * bytes;
215 memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4,
216 colsize, bytes);
217 }
218 } else {
219 if (!((sx+width-1) & 1)) {
220 src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
221 dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
222 memmove_2p_col(dst, src, colsize, bytes);
223 --width;
224 }
225 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
226 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
227 if (width > 1) {
228 src += colsize * bytes + (sx & 1)*3;
229 dst += colsize * bytes + (sx & 1)*3;
230 for(rows = colsize; rows > 0; --rows) {
231 src -= bytes;
232 dst -= bytes;
233 fb_memmove(dst, src, (width>>1)*4);
234 }
235 }
236 if (width & 1)
237 memmove_2p_col(dst-3, src-3, colsize, bytes);
238 }
239 } else {
240
241 if (upwards) {
242 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
243 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
244 for (cols = width; cols > 0; --cols) {
245 memmove_2p_col(dst, src, colsize, bytes);
246 INC_2P(src);
247 INC_2P(dst);
248 }
249 } else {
250 sx += width-1;
251 dx += width-1;
252 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
253 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
254 for(cols = width; cols > 0; --cols) {
255 memmove_2p_col(dst, src, colsize, bytes);
256 DEC_2P(src);
257 DEC_2P(dst);
258 }
259 }
260 }
261 }
262}
263
264void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, int sy,
265 int sx, int height, int width)
266{
267 u32 offset;
268 u8 *start;
269 int rows;
270 int bytes = p->next_line;
271 int lines;
272 u32 size;
273 u32 cval;
274 u16 pcval;
275
276 cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp)));
277
278 if (fontheightlog(p))
279 lines = height << fontheightlog(p);
280 else
281 lines = height * fontheight(p);
282
283 if (sx == 0 && width * 2 == bytes) {
284 if (fontheightlog(p))
285 offset = (sy * bytes) << fontheightlog(p);
286 else
287 offset = sy * bytes * fontheight(p);
288 size = lines * bytes;
289 memset_even_2p(p->screen_base+offset, size, cval);
290 } else {
291 if (fontheightlog(p))
292 offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*4 + (sx & 1);
293 else
294 offset = sy * bytes * fontheight(p) + (sx>>1)*4 + (sx & 1);
295 start = p->screen_base + offset;
296 pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp)));
297
298
299
300
301
302
303
304
305 if (sx & 1) {
306 memclear_2p_col(start, lines, pcval, bytes);
307 start += 3;
308 width--;
309 }
310 if (width & 1) {
311 memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes);
312 width--;
313 }
314 if (width) {
315 for (rows = lines; rows-- ; start += bytes)
316 memset_even_2p(start, width*2, cval);
317 }
318 }
319}
320
321void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c,
322 int yy, int xx)
323{
324 u8 *dest;
325 u8 *cdat;
326 int rows;
327 int bytes = p->next_line;
328 u16 eorx, fgx, bgx, fdx;
329
330 if (fontheightlog(p)) {
331 dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
332 (xx>>1)*4 + (xx & 1));
333 cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p));
334 } else {
335 dest = (p->screen_base + yy * bytes * fontheight(p) +
336 (xx>>1)*4 + (xx & 1));
337 cdat = p->fontdata + (c & p->charmask) * fontheight(p);
338 }
339
340 fgx = expand2w(COLOR_2P(attr_fgcol(p,c)));
341 bgx = expand2w(COLOR_2P(attr_bgcol(p,c)));
342 eorx = fgx ^ bgx;
343
344 for (rows = fontheight(p) ; rows-- ; dest += bytes) {
345 fdx = dup2w(*cdat++);
346 movepw(dest, (fdx & eorx) ^ bgx);
347 }
348}
349
350void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p,
351 const unsigned short *s, int count, int yy, int xx)
352{
353 u8 *dest, *dest0;
354 u8 *cdat;
355 u16 c;
356 int rows;
357 int bytes;
358 u16 eorx, fgx, bgx, fdx;
359
360 bytes = p->next_line;
361 if (fontheightlog(p))
362 dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
363 (xx>>1)*4 + (xx & 1));
364 else
365 dest0 = (p->screen_base + yy * bytes * fontheight(p) +
366 (xx>>1)*4 + (xx & 1));
367 c = scr_readw(s);
368 fgx = expand2w(COLOR_2P(attr_fgcol(p, c)));
369 bgx = expand2w(COLOR_2P(attr_bgcol(p, c)));
370 eorx = fgx ^ bgx;
371
372 while (count--) {
373 c = scr_readw(s++) & p->charmask;
374 if (fontheightlog(p))
375 cdat = p->fontdata + (c << fontheightlog(p));
376 else
377 cdat = p->fontdata + c * fontheight(p);
378
379 for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
380 fdx = dup2w(*cdat++);
381 movepw(dest, (fdx & eorx) ^ bgx);
382 }
383 INC_2P(dest0);
384 }
385}
386
387void fbcon_iplan2p2_revc(struct display *p, int xx, int yy)
388{
389 u8 *dest;
390 int j;
391 int bytes;
392
393 if (fontheightlog(p))
394 dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
395 (xx>>1)*4 + (xx & 1));
396 else
397 dest = (p->screen_base + yy * p->next_line * fontheight(p) +
398 (xx>>1)*4 + (xx & 1));
399 j = fontheight(p);
400 bytes = p->next_line;
401 while (j--) {
402
403
404
405
406 dest[0] = ~dest[0];
407 dest[2] = ~dest[2];
408 dest += bytes;
409 }
410}
411
412void fbcon_iplan2p2_clear_margins(struct vc_data *conp, struct display *p,
413 int bottom_only)
414{
415 u32 offset;
416 int bytes;
417 int lines;
418 u32 cval;
419
420
421
422 bytes = p->next_line;
423 if (fontheightlog(p)) {
424 lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
425 offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
426 } else {
427 lines = p->var.yres - conp->vc_rows * fontheight(p);
428 offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
429 }
430 if (lines) {
431 cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp)));
432 memset_even_2p(p->screen_base+offset, lines * bytes, cval);
433 }
434}
435
436
437
438
439
440
441struct display_switch fbcon_iplan2p2 = {
442 setup: fbcon_iplan2p2_setup,
443 bmove: fbcon_iplan2p2_bmove,
444 clear: fbcon_iplan2p2_clear,
445 putc: fbcon_iplan2p2_putc,
446 putcs: fbcon_iplan2p2_putcs,
447 revc: fbcon_iplan2p2_revc,
448 clear_margins: fbcon_iplan2p2_clear_margins,
449 fontwidthmask: FONTWIDTH(8)
450};
451
452
453#ifdef MODULE
454MODULE_LICENSE("GPL");
455
456int init_module(void)
457{
458 return 0;
459}
460
461void cleanup_module(void)
462{}
463#endif
464
465
466
467
468
469
470EXPORT_SYMBOL(fbcon_iplan2p2);
471EXPORT_SYMBOL(fbcon_iplan2p2_setup);
472EXPORT_SYMBOL(fbcon_iplan2p2_bmove);
473EXPORT_SYMBOL(fbcon_iplan2p2_clear);
474EXPORT_SYMBOL(fbcon_iplan2p2_putc);
475EXPORT_SYMBOL(fbcon_iplan2p2_putcs);
476EXPORT_SYMBOL(fbcon_iplan2p2_revc);
477EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins);
478