diff options
Diffstat (limited to 'drivers/video/fbcon-hga.c')
-rw-r--r-- | drivers/video/fbcon-hga.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/drivers/video/fbcon-hga.c b/drivers/video/fbcon-hga.c new file mode 100644 index 000000000..384e0a917 --- /dev/null +++ b/drivers/video/fbcon-hga.c @@ -0,0 +1,245 @@ +/* + * linux/drivers/video/fbcon-hga.c -- Low level frame buffer operations for + * the Hercules graphics adaptor + * + * Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu) + * Based on fbcon-mfb.c by Geert Uytterhoeven + * + * History: + * + * - Revision 0.1.0 (6 Dec 1999): comment changes + * - First release (25 Nov 1999) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/fb.h> + +#include <video/fbcon.h> +#include <video/fbcon-hga.h> + +#if 0 +#define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args) +#else +#define DPRINTK(args...) +#endif + +#define HGA_ROWADDR(row) ((row%4)*8192 + (row>>2)*90) + + /* + * Hercules monochrome + */ + +static inline u8* rowaddr(struct display *p, u_int row) +{ + return p->screen_base + HGA_ROWADDR(row); +} + +void fbcon_hga_setup(struct display *p) +{ + DPRINTK("fbcon_hga_setup: ll:%d\n", (int)p->line_length); + + p->next_line = p->line_length; + p->next_plane = 0; +} + +void fbcon_hga_bmove(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + u8 *src, *dest; + u_int rows, y1, y2; + +#if 0 + if (sx == 0 && dx == 0 && width == p->next_line) { + src = p->screen_base+sy*fontheight(p)*width; + dest = p->screen_base+dy*fontheight(p)*width; + fb_memmove(dest, src, height*fontheight(p)*width); + } else +#endif + if (dy <= sy) { + y1 = sy*fontheight(p); + y2 = dy*fontheight(p); + for (rows = height*fontheight(p); rows--; ) { + src = rowaddr(p, y1)+sx; + dest = rowaddr(p, y2)+dx; + fb_memmove(dest, src, width); + y1++; + y2++; + } + } else { + y1 = (sy+height)*fontheight(p)-1; + y2 = (dy+height)*fontheight(p)-1; + for (rows = height*fontheight(p); rows--;) { + src = rowaddr(p, y1)+sx; + dest = rowaddr(p, y2)+dx; + fb_memmove(dest, src, width); + y1--; + y2--; + } + } +} + +void fbcon_hga_clear(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u8 *dest; + u_int rows, y; + int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; + + DPRINTK("fbcon_hga_clear: sx:%d, sy:%d, height:%d, width:%d\n", sx, sy, height, width); + + y = sy*fontheight(p); +#if 0 + if (sx == 0 && width == p->next_line) { + if (inverse) { + fb_memset255(dest, height*fontheight(p)*width); + } else { + fb_memclear(dest, height*fontheight(p)*width); + } + } else +#endif + for (rows = height*fontheight(p); rows--; y++) { + dest = rowaddr(p, y)+sx; + if (inverse) { + fb_memset255(dest, width); + } else { + fb_memclear(dest, width); + } + } +} + +void fbcon_hga_putc(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u8 *dest, *cdat; + u_int rows, y, bold, revs, underl; + u8 d; + + cdat = p->fontdata+(c&p->charmask)*fontheight(p); + bold = attr_bold(p, c); + revs = attr_reverse(p, c); + underl = attr_underline(p, c); + y = yy*fontheight(p); + + for (rows = fontheight(p); rows--; y++) { + d = *cdat++; + if (underl && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (revs) + d = ~d; + dest = rowaddr(p, y)+xx; + *dest = d; + } +} + +void fbcon_hga_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, int xx) +{ + u8 *dest, *cdat; + u_int rows, y, y0, bold, revs, underl; + u8 d; + u16 c; + + bold = attr_bold(p,scr_readw(s)); + revs = attr_reverse(p,scr_readw(s)); + underl = attr_underline(p,scr_readw(s)); + y0 = yy*fontheight(p); + + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata+c*fontheight(p); + y = y0; + for (rows = fontheight(p); rows--; y++) { + d = *cdat++; + if (underl && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (revs) + d = ~d; + dest = rowaddr(p, y)+xx; + *dest = d; + } + xx++; + } +} + +void fbcon_hga_revc(struct display *p, int xx, int yy) +{ + u8 *dest; + u_int rows, y; + + y = yy*fontheight(p); + for (rows = fontheight(p); rows--; y++) { + dest = rowaddr(p, y)+xx; + *dest = ~*dest; + } +} + +void fbcon_hga_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + u8 *dest; + u_int height, y; + int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; + + DPRINTK("fbcon_hga_clear_margins: enter\n"); + + /* No need to handle right margin. */ + + y = conp->vc_rows * fontheight(p); + for (height = p->var.yres - y; height-- > 0; y++) { + DPRINTK("fbcon_hga_clear_margins: y:%d, height:%d\n", y, height); + dest = rowaddr(p, y); + if (inverse) { + fb_memset255(dest, p->next_line); + } else { + fb_memclear(dest, p->next_line); + } + } +} + + + /* + * `switch' for the low level operations + */ + +struct display_switch fbcon_hga = { + fbcon_hga_setup, fbcon_hga_bmove, fbcon_hga_clear, fbcon_hga_putc, + fbcon_hga_putcs, fbcon_hga_revc, NULL, NULL, fbcon_hga_clear_margins, + FONTWIDTH(8) +}; + + +#ifdef MODULE +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} +#endif /* MODULE */ + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(fbcon_hga); +EXPORT_SYMBOL(fbcon_hga_setup); +EXPORT_SYMBOL(fbcon_hga_bmove); +EXPORT_SYMBOL(fbcon_hga_clear); +EXPORT_SYMBOL(fbcon_hga_putc); +EXPORT_SYMBOL(fbcon_hga_putcs); +EXPORT_SYMBOL(fbcon_hga_revc); +EXPORT_SYMBOL(fbcon_hga_clear_margins); |