1/*
2 *  linux/drivers/video/fbcon-vga.c -- Low level frame buffer operations for
3 *				       VGA characters/attributes
4 *
5 *	Created 28 Mar 1998 by Geert Uytterhoeven
6 *	Monochrome attributes added May 1998 by Andrew Apted
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 <asm/io.h>
20
21#include <video/fbcon.h>
22#include <video/fbcon-vga.h>
23
24
25    /*
26     *  VGA screen access
27     */
28
29static inline void vga_writew(u16 val, u16 *addr)
30{
31#ifdef __powerpc__
32    st_le16(addr, val);
33#else
34    writew(val, (unsigned long)addr);
35#endif /* !__powerpc__ */
36}
37
38static inline u16 vga_readw(u16 *addr)
39{
40#ifdef __powerpc__
41    return ld_le16(addr);
42#else
43    return readw((unsigned long)addr);
44#endif /* !__powerpc__ */
45}
46
47static inline void vga_memsetw(void *s, u16 c, unsigned int count)
48{
49    u16 *addr = (u16 *)s;
50
51    while (count) {
52	count--;
53	vga_writew(c, addr++);
54    }
55}
56
57static inline void vga_memmovew(u16 *to, u16 *from, unsigned int count)
58{
59    if (to < from) {
60	while (count) {
61	    count--;
62	    vga_writew(vga_readw(from++), to++);
63	}
64    } else {
65	from += count;
66	to += count;
67	while (count) {
68	    count--;
69	    vga_writew(vga_readw(--from), --to);
70	}
71    }
72}
73
74
75    /*
76     *  VGA characters/attributes
77     */
78
79static inline u16 fbcon_vga_attr(struct display *p,
80				 unsigned short s)
81{
82        /* Underline and reverse-video are mutually exclusive on MDA.
83         * Since reverse-video is used for cursors and selected areas,
84	 * it takes precedence.
85         */
86
87	return (attr_reverse(p, s) ? 0x7000 :
88		(attr_underline(p, s) ? 0x0100 : 0x0700)) |
89	       (attr_bold(p, s) ? 0x0800 : 0) |
90	       (attr_blink(p, s) ? 0x8000 : 0);
91}
92
93void fbcon_vga_setup(struct display *p)
94{
95    p->next_line = p->line_length;
96    p->next_plane = 0;
97}
98
99void fbcon_vga_bmove(struct display *p, int sy, int sx, int dy, int dx,
100		     int height, int width)
101{
102    u16 *src, *dst;
103    int rows;
104
105    if (sx == 0 && dx == 0 && width == p->next_line/2) {
106	src = (u16 *)(p->screen_base+sy*p->next_line);
107	dst = (u16 *)(p->screen_base+dy*p->next_line);
108	vga_memmovew(dst, src, height*width);
109    } else if (dy < sy || (dy == sy && dx < sx)) {
110	src = (u16 *)(p->screen_base+sy*p->next_line+sx*2);
111	dst = (u16 *)(p->screen_base+dy*p->next_line+dx*2);
112	for (rows = height; rows-- ;) {
113	    vga_memmovew(dst, src, width);
114	    src += p->next_line/2;
115	    dst += p->next_line/2;
116	}
117    } else {
118	src = (u16 *)(p->screen_base+(sy+height-1)*p->next_line+sx*2);
119	dst = (u16 *)(p->screen_base+(dy+height-1)*p->next_line+dx*2);
120	for (rows = height; rows-- ;) {
121	    vga_memmovew(dst, src, width);
122	    src -= p->next_line/2;
123	    dst -= p->next_line/2;
124	}
125    }
126}
127
128void fbcon_vga_clear(struct vc_data *conp, struct display *p, int sy, int sx,
129		     int height, int width)
130{
131    u16 *dest = (u16 *)(p->screen_base+sy*p->next_line+sx*2);
132    int rows;
133
134    if (sx == 0 && width*2 == p->next_line)
135	vga_memsetw(dest, conp->vc_video_erase_char, height*width);
136    else
137	for (rows = height; rows-- ; dest += p->next_line/2)
138	    vga_memsetw(dest, conp->vc_video_erase_char, width);
139}
140
141void fbcon_vga_putc(struct vc_data *conp, struct display *p, int c, int y,
142		    int x)
143{
144    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
145    if (conp->vc_can_do_color)
146    	vga_writew(c, dst);
147    else
148    	vga_writew(fbcon_vga_attr(p, c) | (c & 0xff), dst);
149}
150
151void fbcon_vga_putcs(struct vc_data *conp, struct display *p,
152		     const unsigned short *s, int count, int y, int x)
153{
154    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
155    u16 sattr;
156    if (conp->vc_can_do_color)
157    	while (count--)
158    	    vga_writew(scr_readw(s++), dst++);
159    else {
160        sattr = fbcon_vga_attr(p, scr_readw(s));
161        while (count--)
162	    vga_writew(sattr | ((int) (scr_readw(s++)) & 0xff), dst++);
163    }
164}
165
166void fbcon_vga_revc(struct display *p, int x, int y)
167{
168    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
169    u16 val = vga_readw(dst);
170    val = (val & 0x88ff) | ((val<<4) & 0x7000) | ((val>>4) & 0x0700);
171    vga_writew(val, dst);
172}
173
174
175    /*
176     *  `switch' for the low level operations
177     */
178
179struct display_switch fbcon_vga = {
180    setup:		fbcon_vga_setup,
181    bmove:		fbcon_vga_bmove,
182    clear:		fbcon_vga_clear,
183    putc:		fbcon_vga_putc,
184    putcs:		fbcon_vga_putcs,
185    revc:		fbcon_vga_revc,
186    fontwidthmask:	FONTWIDTH(8)
187};
188
189
190#ifdef MODULE
191MODULE_LICENSE("GPL");
192
193int init_module(void)
194{
195    return 0;
196}
197
198void cleanup_module(void)
199{}
200#endif /* MODULE */
201
202
203    /*
204     *  Visible symbols for modules
205     */
206
207EXPORT_SYMBOL(fbcon_vga);
208EXPORT_SYMBOL(fbcon_vga_setup);
209EXPORT_SYMBOL(fbcon_vga_bmove);
210EXPORT_SYMBOL(fbcon_vga_clear);
211EXPORT_SYMBOL(fbcon_vga_putc);
212EXPORT_SYMBOL(fbcon_vga_putcs);
213EXPORT_SYMBOL(fbcon_vga_revc);
214