1/*
2 *  linux/drivers/video/cfb4.c -- Low level frame buffer operations for 4 bpp
3 *				  packed pixels
4 *
5 *	Created 26 Dec 1997 by Michael Schmitz
6 *	Based on the old macfb.c 4bpp code by Alan Cox
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/tty.h>
15#include <linux/console.h>
16#include <linux/string.h>
17#include <linux/fb.h>
18
19#include <video/fbcon.h>
20#include <video/fbcon-cfb4.h>
21
22
23    /*
24     *  4 bpp packed pixels
25     */
26
27    /*
28     *  IFF the font is even pixel aligned (that is to say each
29     *  character start is a byte start in the pixel pairs). That
30     *  avoids us having to mask bytes and means we won't be here
31     *  all week. On a MacII that matters _lots_
32     */
33
34static u16 nibbletab_cfb4[] = {
35#if defined(__BIG_ENDIAN)
36    0x0000,0x000f,0x00f0,0x00ff,
37    0x0f00,0x0f0f,0x0ff0,0x0fff,
38    0xf000,0xf00f,0xf0f0,0xf0ff,
39    0xff00,0xff0f,0xfff0,0xffff
40#elif defined(__LITTLE_ENDIAN)
41    0x0000,0xf000,0x0f00,0xff00,
42    0x00f0,0xf0f0,0x0ff0,0xfff0,
43    0x000f,0xf00f,0x0f0f,0xff0f,
44    0x00ff,0xf0ff,0x0fff,0xffff
45#else
46#error FIXME: No endianness??
47#endif
48
49};
50
51void fbcon_cfb4_setup(struct display *p)
52{
53    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual>>1;
54    p->next_plane = 0;
55}
56
57void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
58		      int height, int width)
59{
60	int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
61	u8 *src,*dst;
62
63	if (sx == 0 && dx == 0 && width * 4 == bytes) {
64		fb_memmove(p->screen_base + dy * linesize,
65			  p->screen_base + sy * linesize,
66			  height * linesize);
67	}
68	else {
69		if (dy < sy || (dy == sy && dx < sx)) {
70			src = p->screen_base + sy * linesize + sx * 4;
71			dst = p->screen_base + dy * linesize + dx * 4;
72			for (rows = height * fontheight(p) ; rows-- ;) {
73				fb_memmove(dst, src, width * 4);
74				src += bytes;
75				dst += bytes;
76			}
77		}
78		else {
79			src = p->screen_base + (sy+height) * linesize + sx * 4
80				- bytes;
81			dst = p->screen_base + (dy+height) * linesize + dx * 4
82				- bytes;
83			for (rows = height * fontheight(p) ; rows-- ;) {
84				fb_memmove(dst, src, width * 4);
85				src -= bytes;
86				dst -= bytes;
87			}
88		}
89	}
90}
91
92void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx,
93		      int height, int width)
94{
95	u8 *dest0,*dest;
96	int bytes=p->next_line,lines=height * fontheight(p), rows, i;
97	u32 bgx;
98
99/*	if(p->screen_base!=0xFDD00020)
100		mac_boom(1);*/
101	dest = p->screen_base + sy * fontheight(p) * bytes + sx * 4;
102
103	bgx=attr_bgcol_ec(p,conp);
104	bgx |= (bgx << 4);	/* expand the colour to 32bits */
105	bgx |= (bgx << 8);
106	bgx |= (bgx << 16);
107
108	if (sx == 0 && width * 4 == bytes) {
109		for (i = 0 ; i < lines * width ; i++) {
110			fb_writel (bgx, dest);
111			dest+=4;
112		}
113	} else {
114		dest0=dest;
115		for (rows = lines; rows-- ; dest0 += bytes) {
116			dest=dest0;
117			for (i = 0 ; i < width ; i++) {
118				/* memset ?? */
119				fb_writel (bgx, dest);
120				dest+=4;
121			}
122		}
123	}
124}
125
126void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy,
127		     int xx)
128{
129	u8 *dest,*cdat;
130	int bytes=p->next_line,rows;
131	u32 eorx,fgx,bgx;
132
133	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
134	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
135
136	fgx=attr_fgcol(p,c);
137	bgx=attr_bgcol(p,c);
138	fgx |= (fgx << 4);
139	fgx |= (fgx << 8);
140	bgx |= (bgx << 4);
141	bgx |= (bgx << 8);
142	eorx = fgx ^ bgx;
143
144	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
145		fb_writew((nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx, dest+0);
146		fb_writew((nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx, dest+2);
147	}
148}
149
150void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p,
151		      const unsigned short *s, int count, int yy, int xx)
152{
153	u8 *cdat, *dest, *dest0;
154	u16 c;
155	int rows,bytes=p->next_line;
156	u32 eorx, fgx, bgx;
157
158	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
159	c = scr_readw(s);
160	fgx = attr_fgcol(p, c);
161	bgx = attr_bgcol(p, c);
162	fgx |= (fgx << 4);
163	fgx |= (fgx << 8);
164	fgx |= (fgx << 16);
165	bgx |= (bgx << 4);
166	bgx |= (bgx << 8);
167	bgx |= (bgx << 16);
168	eorx = fgx ^ bgx;
169	while (count--) {
170		c = scr_readw(s++) & p->charmask;
171		cdat = p->fontdata + c * fontheight(p);
172
173		for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
174			fb_writew((nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx, dest+0);
175			fb_writew((nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx, dest+2);
176		}
177		dest0+=4;
178	}
179}
180
181void fbcon_cfb4_revc(struct display *p, int xx, int yy)
182{
183	u8 *dest;
184	int bytes=p->next_line, rows;
185
186	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
187	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
188		fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
189	}
190}
191
192
193    /*
194     *  `switch' for the low level operations
195     */
196
197struct display_switch fbcon_cfb4 = {
198    setup:		fbcon_cfb4_setup,
199    bmove:		fbcon_cfb4_bmove,
200    clear:		fbcon_cfb4_clear,
201    putc:		fbcon_cfb4_putc,
202    putcs:		fbcon_cfb4_putcs,
203    revc:		fbcon_cfb4_revc,
204    fontwidthmask:	FONTWIDTH(8)
205};
206
207
208#ifdef MODULE
209MODULE_LICENSE("GPL");
210
211int init_module(void)
212{
213    return 0;
214}
215
216void cleanup_module(void)
217{}
218#endif /* MODULE */
219
220
221    /*
222     *  Visible symbols for modules
223     */
224
225EXPORT_SYMBOL(fbcon_cfb4);
226EXPORT_SYMBOL(fbcon_cfb4_setup);
227EXPORT_SYMBOL(fbcon_cfb4_bmove);
228EXPORT_SYMBOL(fbcon_cfb4_clear);
229EXPORT_SYMBOL(fbcon_cfb4_putc);
230EXPORT_SYMBOL(fbcon_cfb4_putcs);
231EXPORT_SYMBOL(fbcon_cfb4_revc);
232