cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vga16fb.c (38818B)


      1/*
      2 * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
      3 * 
      4 * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
      5 * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
      6 * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
      7 *
      8 * This file is subject to the terms and conditions of the GNU General
      9 * Public License.  See the file COPYING in the main directory of this
     10 * archive for more details.  
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/kernel.h>
     15#include <linux/errno.h>
     16#include <linux/string.h>
     17#include <linux/mm.h>
     18#include <linux/delay.h>
     19#include <linux/fb.h>
     20#include <linux/ioport.h>
     21#include <linux/init.h>
     22#include <linux/platform_device.h>
     23#include <linux/screen_info.h>
     24
     25#include <asm/io.h>
     26#include <video/vga.h>
     27
     28#define VGA_FB_PHYS 0xA0000
     29#define VGA_FB_PHYS_LEN 65536
     30
     31#define MODE_SKIP4	1
     32#define MODE_8BPP	2
     33#define MODE_CFB	4
     34#define MODE_TEXT	8
     35
     36/* --------------------------------------------------------------------- */
     37
     38/*
     39 * card parameters
     40 */
     41
     42struct vga16fb_par {
     43	/* structure holding original VGA register settings when the
     44           screen is blanked */
     45	struct {
     46		unsigned char	SeqCtrlIndex;	  /* Sequencer Index reg.   */
     47		unsigned char	CrtCtrlIndex;	  /* CRT-Contr. Index reg.  */
     48		unsigned char	CrtMiscIO;	  /* Miscellaneous register */
     49		unsigned char	HorizontalTotal;  /* CRT-Controller:00h */
     50		unsigned char	HorizDisplayEnd;  /* CRT-Controller:01h */
     51		unsigned char	StartHorizRetrace;/* CRT-Controller:04h */
     52		unsigned char	EndHorizRetrace;  /* CRT-Controller:05h */
     53		unsigned char	Overflow;	  /* CRT-Controller:07h */
     54		unsigned char	StartVertRetrace; /* CRT-Controller:10h */
     55		unsigned char	EndVertRetrace;	  /* CRT-Controller:11h */
     56		unsigned char	ModeControl;	  /* CRT-Controller:17h */
     57		unsigned char	ClockingMode;	  /* Seq-Controller:01h */
     58	} vga_state;
     59	struct vgastate state;
     60	unsigned int ref_count;
     61	int palette_blanked, vesa_blanked, mode, isVGA;
     62	u8 misc, pel_msk, vss, clkdiv;
     63	u8 crtc[VGA_CRT_C];
     64};
     65
     66/* --------------------------------------------------------------------- */
     67
     68static struct fb_var_screeninfo vga16fb_defined = {
     69	.xres		= 640,
     70	.yres		= 480,
     71	.xres_virtual	= 640,
     72	.yres_virtual	= 480,
     73	.bits_per_pixel	= 4,	
     74	.activate	= FB_ACTIVATE_TEST,
     75	.height		= -1,
     76	.width		= -1,
     77	.pixclock	= 39721,
     78	.left_margin	= 48,
     79	.right_margin	= 16,
     80	.upper_margin	= 33,
     81	.lower_margin	= 10,
     82	.hsync_len 	= 96,
     83	.vsync_len	= 2,
     84	.vmode		= FB_VMODE_NONINTERLACED,
     85};
     86
     87/* name should not depend on EGA/VGA */
     88static const struct fb_fix_screeninfo vga16fb_fix = {
     89	.id		= "VGA16 VGA",
     90	.smem_start	= VGA_FB_PHYS,
     91	.smem_len	= VGA_FB_PHYS_LEN,
     92	.type		= FB_TYPE_VGA_PLANES,
     93	.type_aux	= FB_AUX_VGA_PLANES_VGA4,
     94	.visual		= FB_VISUAL_PSEUDOCOLOR,
     95	.xpanstep	= 8,
     96	.ypanstep	= 1,
     97	.line_length	= 640 / 8,
     98	.accel		= FB_ACCEL_NONE
     99};
    100
    101/* The VGA's weird architecture often requires that we read a byte and
    102   write a byte to the same location.  It doesn't matter *what* byte
    103   we write, however.  This is because all the action goes on behind
    104   the scenes in the VGA's 32-bit latch register, and reading and writing
    105   video memory just invokes latch behavior.
    106
    107   To avoid race conditions (is this necessary?), reading and writing
    108   the memory byte should be done with a single instruction.  One
    109   suitable instruction is the x86 bitwise OR.  The following
    110   read-modify-write routine should optimize to one such bitwise
    111   OR. */
    112static inline void rmw(volatile char __iomem *p)
    113{
    114	readb(p);
    115	writeb(1, p);
    116}
    117
    118/* Set the Graphics Mode Register, and return its previous value.
    119   Bits 0-1 are write mode, bit 3 is read mode. */
    120static inline int setmode(int mode)
    121{
    122	int oldmode;
    123	
    124	oldmode = vga_io_rgfx(VGA_GFX_MODE);
    125	vga_io_w(VGA_GFX_D, mode);
    126	return oldmode;
    127}
    128
    129/* Select the Bit Mask Register and return its value. */
    130static inline int selectmask(void)
    131{
    132	return vga_io_rgfx(VGA_GFX_BIT_MASK);
    133}
    134
    135/* Set the value of the Bit Mask Register.  It must already have been
    136   selected with selectmask(). */
    137static inline void setmask(int mask)
    138{
    139	vga_io_w(VGA_GFX_D, mask);
    140}
    141
    142/* Set the Data Rotate Register and return its old value. 
    143   Bits 0-2 are rotate count, bits 3-4 are logical operation
    144   (0=NOP, 1=AND, 2=OR, 3=XOR). */
    145static inline int setop(int op)
    146{
    147	int oldop;
    148	
    149	oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
    150	vga_io_w(VGA_GFX_D, op);
    151	return oldop;
    152}
    153
    154/* Set the Enable Set/Reset Register and return its old value.  
    155   The code here always uses value 0xf for this register. */
    156static inline int setsr(int sr)
    157{
    158	int oldsr;
    159
    160	oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
    161	vga_io_w(VGA_GFX_D, sr);
    162	return oldsr;
    163}
    164
    165/* Set the Set/Reset Register and return its old value. */
    166static inline int setcolor(int color)
    167{
    168	int oldcolor;
    169
    170	oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
    171	vga_io_w(VGA_GFX_D, color);
    172	return oldcolor;
    173}
    174
    175/* Return the value in the Graphics Address Register. */
    176static inline int getindex(void)
    177{
    178	return vga_io_r(VGA_GFX_I);
    179}
    180
    181/* Set the value in the Graphics Address Register. */
    182static inline void setindex(int index)
    183{
    184	vga_io_w(VGA_GFX_I, index);
    185}
    186
    187/* Check if the video mode is supported by the driver */
    188static inline int check_mode_supported(void)
    189{
    190	/* non-x86 architectures treat orig_video_isVGA as a boolean flag */
    191#if defined(CONFIG_X86)
    192	/* only EGA and VGA in 16 color graphic mode are supported */
    193	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EGAC &&
    194	    screen_info.orig_video_isVGA != VIDEO_TYPE_VGAC)
    195		return -ENODEV;
    196
    197	if (screen_info.orig_video_mode != 0x0D &&	/* 320x200/4 (EGA) */
    198	    screen_info.orig_video_mode != 0x0E &&	/* 640x200/4 (EGA) */
    199	    screen_info.orig_video_mode != 0x10 &&	/* 640x350/4 (EGA) */
    200	    screen_info.orig_video_mode != 0x12)	/* 640x480/4 (VGA) */
    201		return -ENODEV;
    202#endif
    203	return 0;
    204}
    205
    206static void vga16fb_pan_var(struct fb_info *info, 
    207			    struct fb_var_screeninfo *var)
    208{
    209	struct vga16fb_par *par = info->par;
    210	u32 xoffset, pos;
    211
    212	xoffset = var->xoffset;
    213	if (info->var.bits_per_pixel == 8) {
    214		pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
    215	} else if (par->mode & MODE_TEXT) {
    216		int fh = 16; // FIXME !!! font height. Fugde for now.
    217		pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
    218	} else {
    219		if (info->var.nonstd)
    220			xoffset--;
    221		pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
    222	}
    223	vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
    224	vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
    225	/* if we support CFB4, then we must! support xoffset with pixel
    226	 * granularity if someone supports xoffset in bit resolution */
    227	vga_io_r(VGA_IS1_RC);		/* reset flip-flop */
    228	vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
    229	if (info->var.bits_per_pixel == 8)
    230		vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
    231	else
    232		vga_io_w(VGA_ATT_IW, xoffset & 7);
    233	vga_io_r(VGA_IS1_RC);
    234	vga_io_w(VGA_ATT_IW, 0x20);
    235}
    236
    237static void vga16fb_update_fix(struct fb_info *info)
    238{
    239	if (info->var.bits_per_pixel == 4) {
    240		if (info->var.nonstd) {
    241			info->fix.type = FB_TYPE_PACKED_PIXELS;
    242			info->fix.line_length = info->var.xres_virtual / 2;
    243		} else {
    244			info->fix.type = FB_TYPE_VGA_PLANES;
    245			info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
    246			info->fix.line_length = info->var.xres_virtual / 8;
    247		}
    248	} else if (info->var.bits_per_pixel == 0) {
    249		info->fix.type = FB_TYPE_TEXT;
    250		info->fix.type_aux = FB_AUX_TEXT_CGA;
    251		info->fix.line_length = info->var.xres_virtual / 4;
    252	} else {	/* 8bpp */
    253		if (info->var.nonstd) {
    254			info->fix.type = FB_TYPE_VGA_PLANES;
    255			info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
    256			info->fix.line_length = info->var.xres_virtual / 4;
    257		} else {
    258			info->fix.type = FB_TYPE_PACKED_PIXELS;
    259			info->fix.line_length = info->var.xres_virtual;
    260		}
    261	}
    262}
    263
    264static void vga16fb_clock_chip(struct vga16fb_par *par,
    265			       unsigned int *pixclock,
    266			       const struct fb_info *info,
    267			       int mul, int div)
    268{
    269	static const struct {
    270		u32 pixclock;
    271		u8  misc;
    272		u8  seq_clock_mode;
    273	} *ptr, *best, vgaclocks[] = {
    274		{ 79442 /* 12.587 */, 0x00, 0x08},
    275		{ 70616 /* 14.161 */, 0x04, 0x08},
    276		{ 39721 /* 25.175 */, 0x00, 0x00},
    277		{ 35308 /* 28.322 */, 0x04, 0x00},
    278		{     0 /* bad */,    0x00, 0x00}};
    279	int err;
    280
    281	*pixclock = (*pixclock * mul) / div;
    282	best = vgaclocks;
    283	err = *pixclock - best->pixclock;
    284	if (err < 0) err = -err;
    285	for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
    286		int tmp;
    287
    288		tmp = *pixclock - ptr->pixclock;
    289		if (tmp < 0) tmp = -tmp;
    290		if (tmp < err) {
    291			err = tmp;
    292			best = ptr;
    293		}
    294	}
    295	par->misc |= best->misc;
    296	par->clkdiv = best->seq_clock_mode;
    297	*pixclock = (best->pixclock * div) / mul;
    298}
    299			       
    300#define FAIL(X) return -EINVAL
    301
    302static int vga16fb_open(struct fb_info *info, int user)
    303{
    304	struct vga16fb_par *par = info->par;
    305
    306	if (!par->ref_count) {
    307		memset(&par->state, 0, sizeof(struct vgastate));
    308		par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
    309			VGA_SAVE_CMAP;
    310		save_vga(&par->state);
    311	}
    312	par->ref_count++;
    313
    314	return 0;
    315}
    316
    317static int vga16fb_release(struct fb_info *info, int user)
    318{
    319	struct vga16fb_par *par = info->par;
    320
    321	if (!par->ref_count)
    322		return -EINVAL;
    323
    324	if (par->ref_count == 1)
    325		restore_vga(&par->state);
    326	par->ref_count--;
    327
    328	return 0;
    329}
    330
    331static int vga16fb_check_var(struct fb_var_screeninfo *var,
    332			     struct fb_info *info)
    333{
    334	struct vga16fb_par *par = info->par;
    335	u32 xres, right, hslen, left, xtotal;
    336	u32 yres, lower, vslen, upper, ytotal;
    337	u32 vxres, xoffset, vyres, yoffset;
    338	u32 pos;
    339	u8 r7, rMode;
    340	int shift;
    341	int mode;
    342	u32 maxmem;
    343
    344	par->pel_msk = 0xFF;
    345
    346	if (var->bits_per_pixel == 4) {
    347		if (var->nonstd) {
    348			if (!par->isVGA)
    349				return -EINVAL;
    350			shift = 3;
    351			mode = MODE_SKIP4 | MODE_CFB;
    352			maxmem = 16384;
    353			par->pel_msk = 0x0F;
    354		} else {
    355			shift = 3;
    356			mode = 0;
    357			maxmem = 65536;
    358		}
    359	} else if (var->bits_per_pixel == 8) {
    360		if (!par->isVGA)
    361			return -EINVAL;	/* no support on EGA */
    362		shift = 2;
    363		if (var->nonstd) {
    364			mode = MODE_8BPP | MODE_CFB;
    365			maxmem = 65536;
    366		} else {
    367			mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
    368			maxmem = 16384;
    369		}
    370	} else
    371		return -EINVAL;
    372
    373	xres = (var->xres + 7) & ~7;
    374	vxres = (var->xres_virtual + 0xF) & ~0xF;
    375	xoffset = (var->xoffset + 7) & ~7;
    376	left = (var->left_margin + 7) & ~7;
    377	right = (var->right_margin + 7) & ~7;
    378	hslen = (var->hsync_len + 7) & ~7;
    379
    380	if (vxres < xres)
    381		vxres = xres;
    382	if (xres + xoffset > vxres)
    383		xoffset = vxres - xres;
    384
    385	var->xres = xres;
    386	var->right_margin = right;
    387	var->hsync_len = hslen;
    388	var->left_margin = left;
    389	var->xres_virtual = vxres;
    390	var->xoffset = xoffset;
    391
    392	xres >>= shift;
    393	right >>= shift;
    394	hslen >>= shift;
    395	left >>= shift;
    396	vxres >>= shift;
    397	xtotal = xres + right + hslen + left;
    398	if (xtotal >= 256)
    399		FAIL("xtotal too big");
    400	if (hslen > 32)
    401		FAIL("hslen too big");
    402	if (right + hslen + left > 64)
    403		FAIL("hblank too big");
    404	par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
    405	par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
    406	par->crtc[VGA_CRTC_H_DISP] = xres - 1;
    407	pos = xres + right;
    408	par->crtc[VGA_CRTC_H_SYNC_START] = pos;
    409	pos += hslen;
    410	par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
    411	pos += left - 2; /* blank_end + 2 <= total + 5 */
    412	par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
    413	if (pos & 0x20)
    414		par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
    415
    416	yres = var->yres;
    417	lower = var->lower_margin;
    418	vslen = var->vsync_len;
    419	upper = var->upper_margin;
    420	vyres = var->yres_virtual;
    421	yoffset = var->yoffset;
    422
    423	if (yres > vyres)
    424		vyres = yres;
    425	if (vxres * vyres > maxmem) {
    426		vyres = maxmem / vxres;
    427		if (vyres < yres)
    428			return -ENOMEM;
    429	}
    430	if (yoffset + yres > vyres)
    431		yoffset = vyres - yres;
    432	var->yres = yres;
    433	var->lower_margin = lower;
    434	var->vsync_len = vslen;
    435	var->upper_margin = upper;
    436	var->yres_virtual = vyres;
    437	var->yoffset = yoffset;
    438
    439	if (var->vmode & FB_VMODE_DOUBLE) {
    440		yres <<= 1;
    441		lower <<= 1;
    442		vslen <<= 1;
    443		upper <<= 1;
    444	}
    445	ytotal = yres + lower + vslen + upper;
    446	if (ytotal > 1024) {
    447		ytotal >>= 1;
    448		yres >>= 1;
    449		lower >>= 1;
    450		vslen >>= 1;
    451		upper >>= 1;
    452		rMode = 0x04;
    453	} else
    454		rMode = 0x00;
    455	if (ytotal > 1024)
    456		FAIL("ytotal too big");
    457	if (vslen > 16)
    458		FAIL("vslen too big");
    459	par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
    460	r7 = 0x10;	/* disable linecompare */
    461	if (ytotal & 0x100) r7 |= 0x01;
    462	if (ytotal & 0x200) r7 |= 0x20;
    463	par->crtc[VGA_CRTC_PRESET_ROW] = 0;
    464	par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;	/* 1 scanline, no linecmp */
    465	if (var->vmode & FB_VMODE_DOUBLE)
    466		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
    467	par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
    468	par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
    469	if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
    470		xoffset--;
    471	pos = yoffset * vxres + (xoffset >> shift);
    472	par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
    473	par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
    474	par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
    475	par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
    476	pos = yres - 1;
    477	par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
    478	par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
    479	if (pos & 0x100)
    480		r7 |= 0x0A;	/* 0x02 -> DISP_END, 0x08 -> BLANK_START */
    481	if (pos & 0x200) {
    482		r7 |= 0x40;	/* 0x40 -> DISP_END */
    483		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
    484	}
    485	pos += lower;
    486	par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
    487	if (pos & 0x100)
    488		r7 |= 0x04;
    489	if (pos & 0x200)
    490		r7 |= 0x80;
    491	pos += vslen;
    492	par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
    493	pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
    494	par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
    495                     but some SVGA chips requires all 8 bits to set */
    496	if (vxres >= 512)
    497		FAIL("vxres too long");
    498	par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
    499	if (mode & MODE_SKIP4)
    500		par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;	/* 256, cfb8 */
    501	else
    502		par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;	/* 16, vgap */
    503	par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
    504	par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
    505	par->crtc[VGA_CRTC_OVERFLOW] = r7;
    506
    507	par->vss = 0x00;	/* 3DA */
    508
    509	par->misc = 0xE3;	/* enable CPU, ports 0x3Dx, positive sync */
    510	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
    511		par->misc &= ~0x40;
    512	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
    513		par->misc &= ~0x80;
    514	
    515	par->mode = mode;
    516
    517	if (mode & MODE_8BPP)
    518		/* pixel clock == vga clock / 2 */
    519		vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
    520	else
    521		/* pixel clock == vga clock */
    522		vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
    523	
    524	var->red.offset = var->green.offset = var->blue.offset = 
    525	var->transp.offset = 0;
    526	var->red.length = var->green.length = var->blue.length =
    527		(par->isVGA) ? 6 : 2;
    528	var->transp.length = 0;
    529	var->activate = FB_ACTIVATE_NOW;
    530	var->height = -1;
    531	var->width = -1;
    532	var->accel_flags = 0;
    533	return 0;
    534}
    535#undef FAIL
    536
    537static int vga16fb_set_par(struct fb_info *info)
    538{
    539	struct vga16fb_par *par = info->par;
    540	u8 gdc[VGA_GFX_C];
    541	u8 seq[VGA_SEQ_C];
    542	u8 atc[VGA_ATT_C];
    543	int fh, i;
    544
    545	seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
    546	if (par->mode & MODE_TEXT)
    547		seq[VGA_SEQ_PLANE_WRITE] = 0x03;
    548	else
    549		seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
    550	seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
    551	if (par->mode & MODE_TEXT)
    552		seq[VGA_SEQ_MEMORY_MODE] = 0x03;
    553	else if (par->mode & MODE_SKIP4)
    554		seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
    555	else
    556		seq[VGA_SEQ_MEMORY_MODE] = 0x06;
    557
    558	gdc[VGA_GFX_SR_VALUE] = 0x00;
    559	gdc[VGA_GFX_SR_ENABLE] = 0x00;
    560	gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
    561	gdc[VGA_GFX_DATA_ROTATE] = 0x00;
    562	gdc[VGA_GFX_PLANE_READ] = 0;
    563	if (par->mode & MODE_TEXT) {
    564		gdc[VGA_GFX_MODE] = 0x10;
    565		gdc[VGA_GFX_MISC] = 0x06;
    566	} else {
    567		if (par->mode & MODE_CFB)
    568			gdc[VGA_GFX_MODE] = 0x40;
    569		else
    570			gdc[VGA_GFX_MODE] = 0x00;
    571		gdc[VGA_GFX_MISC] = 0x05;
    572	}
    573	gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
    574	gdc[VGA_GFX_BIT_MASK] = 0xFF;
    575
    576	for (i = 0x00; i < 0x10; i++)
    577		atc[i] = i;
    578	if (par->mode & MODE_TEXT)
    579		atc[VGA_ATC_MODE] = 0x04;
    580	else if (par->mode & MODE_8BPP)
    581		atc[VGA_ATC_MODE] = 0x41;
    582	else
    583		atc[VGA_ATC_MODE] = 0x81;
    584	atc[VGA_ATC_OVERSCAN] = 0x00;	/* 0 for EGA, 0xFF for VGA */
    585	atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
    586	if (par->mode & MODE_8BPP)
    587		atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
    588	else
    589		atc[VGA_ATC_PEL] = info->var.xoffset & 7;
    590	atc[VGA_ATC_COLOR_PAGE] = 0x00;
    591	
    592	if (par->mode & MODE_TEXT) {
    593		fh = 16; // FIXME !!! Fudge font height. 
    594		par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] 
    595					       & ~0x1F) | (fh - 1);
    596	}
    597
    598	vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
    599
    600	/* Enable graphics register modification */
    601	if (!par->isVGA) {
    602		vga_io_w(EGA_GFX_E0, 0x00);
    603		vga_io_w(EGA_GFX_E1, 0x01);
    604	}
    605	
    606	/* update misc output register */
    607	vga_io_w(VGA_MIS_W, par->misc);
    608	
    609	/* synchronous reset on */
    610	vga_io_wseq(0x00, 0x01);
    611
    612	if (par->isVGA)
    613		vga_io_w(VGA_PEL_MSK, par->pel_msk);
    614
    615	/* write sequencer registers */
    616	vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
    617	for (i = 2; i < VGA_SEQ_C; i++) {
    618		vga_io_wseq(i, seq[i]);
    619	}
    620	
    621	/* synchronous reset off */
    622	vga_io_wseq(0x00, 0x03);
    623
    624	/* deprotect CRT registers 0-7 */
    625	vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
    626
    627	/* write CRT registers */
    628	for (i = 0; i < VGA_CRTC_REGS; i++) {
    629		vga_io_wcrt(i, par->crtc[i]);
    630	}
    631	
    632	/* write graphics controller registers */
    633	for (i = 0; i < VGA_GFX_C; i++) {
    634		vga_io_wgfx(i, gdc[i]);
    635	}
    636	
    637	/* write attribute controller registers */
    638	for (i = 0; i < VGA_ATT_C; i++) {
    639		vga_io_r(VGA_IS1_RC);		/* reset flip-flop */
    640		vga_io_wattr(i, atc[i]);
    641	}
    642
    643	/* Wait for screen to stabilize. */
    644	mdelay(50);
    645
    646	vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
    647
    648	vga_io_r(VGA_IS1_RC);
    649	vga_io_w(VGA_ATT_IW, 0x20);
    650
    651	vga16fb_update_fix(info);
    652	return 0;
    653}
    654
    655static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
    656{
    657	static const unsigned char map[] = { 000, 001, 010, 011 };
    658	int val;
    659	
    660	if (regno >= 16)
    661		return;
    662	val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
    663	vga_io_r(VGA_IS1_RC);   /* ! 0x3BA */
    664	vga_io_wattr(regno, val);
    665	vga_io_r(VGA_IS1_RC);   /* some clones need it */
    666	vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
    667}
    668
    669static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
    670{
    671	outb(regno,       VGA_PEL_IW);
    672	outb(red   >> 10, VGA_PEL_D);
    673	outb(green >> 10, VGA_PEL_D);
    674	outb(blue  >> 10, VGA_PEL_D);
    675}
    676
    677static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
    678			     unsigned blue, unsigned transp,
    679			     struct fb_info *info)
    680{
    681	struct vga16fb_par *par = info->par;
    682	int gray;
    683
    684	/*
    685	 *  Set a single color register. The values supplied are
    686	 *  already rounded down to the hardware's capabilities
    687	 *  (according to the entries in the `var' structure). Return
    688	 *  != 0 for invalid regno.
    689	 */
    690	
    691	if (regno >= 256)
    692		return 1;
    693
    694	gray = info->var.grayscale;
    695	
    696	if (gray) {
    697		/* gray = 0.30*R + 0.59*G + 0.11*B */
    698		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
    699	}
    700	if (par->isVGA) 
    701		vga16_setpalette(regno,red,green,blue);
    702	else
    703		ega16_setpalette(regno,red,green,blue);
    704	return 0;
    705}
    706
    707static int vga16fb_pan_display(struct fb_var_screeninfo *var,
    708			       struct fb_info *info) 
    709{
    710	vga16fb_pan_var(info, var);
    711	return 0;
    712}
    713
    714/* The following VESA blanking code is taken from vgacon.c.  The VGA
    715   blanking code was originally by Huang shi chao, and modified by
    716   Christoph Rimek (chrimek@toppoint.de) and todd j. derr
    717   (tjd@barefoot.org) for Linux. */
    718
    719static void vga_vesa_blank(struct vga16fb_par *par, int mode)
    720{
    721	unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
    722	unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
    723	
    724	/* save original values of VGA controller registers */
    725	if(!par->vesa_blanked) {
    726		par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
    727		//sti();
    728
    729		par->vga_state.HorizontalTotal = vga_io_rcrt(0x00);	/* HorizontalTotal */
    730		par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01);	/* HorizDisplayEnd */
    731		par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);	/* StartHorizRetrace */
    732		par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05);	/* EndHorizRetrace */
    733		par->vga_state.Overflow = vga_io_rcrt(0x07);		/* Overflow */
    734		par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);	/* StartVertRetrace */
    735		par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);	/* EndVertRetrace */
    736		par->vga_state.ModeControl = vga_io_rcrt(0x17);	/* ModeControl */
    737		par->vga_state.ClockingMode = vga_io_rseq(0x01);	/* ClockingMode */
    738	}
    739
    740	/* assure that video is enabled */
    741	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
    742	vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
    743
    744	/* test for vertical retrace in process.... */
    745	if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
    746		vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
    747
    748	/*
    749	 * Set <End of vertical retrace> to minimum (0) and
    750	 * <Start of vertical Retrace> to maximum (incl. overflow)
    751	 * Result: turn off vertical sync (VSync) pulse.
    752	 */
    753	if (mode & FB_BLANK_VSYNC_SUSPEND) {
    754		vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
    755		vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
    756		/* bits 9,10 of vert. retrace */
    757		vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
    758	}
    759
    760	if (mode & FB_BLANK_HSYNC_SUSPEND) {
    761		/*
    762		 * Set <End of horizontal retrace> to minimum (0) and
    763		 *  <Start of horizontal Retrace> to maximum
    764		 * Result: turn off horizontal sync (HSync) pulse.
    765		 */
    766		vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
    767		vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
    768	}
    769
    770	/* restore both index registers */
    771	outb_p(SeqCtrlIndex, VGA_SEQ_I);
    772	outb_p(CrtCtrlIndex, VGA_CRT_IC);
    773}
    774
    775static void vga_vesa_unblank(struct vga16fb_par *par)
    776{
    777	unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
    778	unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
    779	
    780	/* restore original values of VGA controller registers */
    781	vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
    782
    783	/* HorizontalTotal */
    784	vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
    785	/* HorizDisplayEnd */
    786	vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
    787	/* StartHorizRetrace */
    788	vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
    789	/* EndHorizRetrace */
    790	vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
    791	/* Overflow */
    792	vga_io_wcrt(0x07, par->vga_state.Overflow);
    793	/* StartVertRetrace */
    794	vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
    795	/* EndVertRetrace */
    796	vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
    797	/* ModeControl */
    798	vga_io_wcrt(0x17, par->vga_state.ModeControl);
    799	/* ClockingMode */
    800	vga_io_wseq(0x01, par->vga_state.ClockingMode);
    801
    802	/* restore index/control registers */
    803	vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
    804	vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
    805}
    806
    807static void vga_pal_blank(void)
    808{
    809	int i;
    810
    811	for (i=0; i<16; i++) {
    812		outb_p(i, VGA_PEL_IW);
    813		outb_p(0, VGA_PEL_D);
    814		outb_p(0, VGA_PEL_D);
    815		outb_p(0, VGA_PEL_D);
    816	}
    817}
    818
    819/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
    820static int vga16fb_blank(int blank, struct fb_info *info)
    821{
    822	struct vga16fb_par *par = info->par;
    823
    824	switch (blank) {
    825	case FB_BLANK_UNBLANK:				/* Unblank */
    826		if (par->vesa_blanked) {
    827			vga_vesa_unblank(par);
    828			par->vesa_blanked = 0;
    829		}
    830		if (par->palette_blanked) {
    831			par->palette_blanked = 0;
    832		}
    833		break;
    834	case FB_BLANK_NORMAL:				/* blank */
    835		vga_pal_blank();
    836		par->palette_blanked = 1;
    837		break;
    838	default:			/* VESA blanking */
    839		vga_vesa_blank(par, blank);
    840		par->vesa_blanked = 1;
    841		break;
    842	}
    843	return 0;
    844}
    845
    846static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
    847{
    848	u32 dx = rect->dx, width = rect->width;
    849        char oldindex = getindex();
    850        char oldmode = setmode(0x40);
    851        char oldmask = selectmask();
    852        int line_ofs, height;
    853        char oldop, oldsr;
    854        char __iomem *where;
    855
    856        dx /= 4;
    857        where = info->screen_base + dx + rect->dy * info->fix.line_length;
    858
    859        if (rect->rop == ROP_COPY) {
    860                oldop = setop(0);
    861                oldsr = setsr(0);
    862
    863                width /= 4;
    864                line_ofs = info->fix.line_length - width;
    865                setmask(0xff);
    866
    867                height = rect->height;
    868
    869                while (height--) {
    870                        int x;
    871
    872                        /* we can do memset... */
    873                        for (x = width; x > 0; --x) {
    874                                writeb(rect->color, where);
    875                                where++;
    876                        }
    877                        where += line_ofs;
    878                }
    879        } else {
    880                char oldcolor = setcolor(0xf);
    881                int y;
    882
    883                oldop = setop(0x18);
    884                oldsr = setsr(0xf);
    885                setmask(0x0F);
    886                for (y = 0; y < rect->height; y++) {
    887                        rmw(where);
    888                        rmw(where+1);
    889                        where += info->fix.line_length;
    890                }
    891                setcolor(oldcolor);
    892        }
    893        setmask(oldmask);
    894        setsr(oldsr);
    895        setop(oldop);
    896        setmode(oldmode);
    897        setindex(oldindex);
    898}
    899
    900static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
    901{
    902	int x, x2, y2, vxres, vyres, width, height, line_ofs;
    903	char __iomem *dst;
    904
    905	vxres = info->var.xres_virtual;
    906	vyres = info->var.yres_virtual;
    907
    908	if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
    909		return;
    910
    911	/* We could use hardware clipping but on many cards you get around
    912	 * hardware clipping by writing to framebuffer directly. */
    913
    914	x2 = rect->dx + rect->width;
    915	y2 = rect->dy + rect->height;
    916	x2 = x2 < vxres ? x2 : vxres;
    917	y2 = y2 < vyres ? y2 : vyres;
    918	width = x2 - rect->dx;
    919
    920	switch (info->fix.type) {
    921	case FB_TYPE_VGA_PLANES:
    922		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
    923
    924			height = y2 - rect->dy;
    925			width = rect->width/8;
    926
    927			line_ofs = info->fix.line_length - width;
    928			dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
    929
    930			switch (rect->rop) {
    931			case ROP_COPY:
    932				setmode(0);
    933				setop(0);
    934				setsr(0xf);
    935				setcolor(rect->color);
    936				selectmask();
    937
    938				setmask(0xff);
    939
    940				while (height--) {
    941					for (x = 0; x < width; x++) {
    942						writeb(0, dst);
    943						dst++;
    944					}
    945					dst += line_ofs;
    946				}
    947				break;
    948			case ROP_XOR:
    949				setmode(0);
    950				setop(0x18);
    951				setsr(0xf);
    952				setcolor(0xf);
    953				selectmask();
    954
    955				setmask(0xff);
    956				while (height--) {
    957					for (x = 0; x < width; x++) {
    958						rmw(dst);
    959						dst++;
    960					}
    961					dst += line_ofs;
    962				}
    963				break;
    964			}
    965		} else 
    966			vga_8planes_fillrect(info, rect);
    967		break;
    968	case FB_TYPE_PACKED_PIXELS:
    969	default:
    970		cfb_fillrect(info, rect);
    971		break;
    972	}
    973}
    974
    975static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
    976{
    977        char oldindex = getindex();
    978        char oldmode = setmode(0x41);
    979        char oldop = setop(0);
    980        char oldsr = setsr(0xf);
    981        int height, line_ofs, x;
    982	u32 sx, dx, width;
    983	char __iomem *dest;
    984	char __iomem *src;
    985
    986        height = area->height;
    987
    988        sx = area->sx / 4;
    989        dx = area->dx / 4;
    990        width = area->width / 4;
    991
    992        if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
    993                line_ofs = info->fix.line_length - width;
    994                dest = info->screen_base + dx + area->dy * info->fix.line_length;
    995                src = info->screen_base + sx + area->sy * info->fix.line_length;
    996                while (height--) {
    997                        for (x = 0; x < width; x++) {
    998                                readb(src);
    999                                writeb(0, dest);
   1000                                src++;
   1001                                dest++;
   1002                        }
   1003                        src += line_ofs;
   1004                        dest += line_ofs;
   1005                }
   1006        } else {
   1007                line_ofs = info->fix.line_length - width;
   1008                dest = info->screen_base + dx + width +
   1009			(area->dy + height - 1) * info->fix.line_length;
   1010                src = info->screen_base + sx + width +
   1011			(area->sy + height - 1) * info->fix.line_length;
   1012                while (height--) {
   1013                        for (x = 0; x < width; x++) {
   1014                                --src;
   1015                                --dest;
   1016                                readb(src);
   1017                                writeb(0, dest);
   1018                        }
   1019                        src -= line_ofs;
   1020                        dest -= line_ofs;
   1021                }
   1022        }
   1023
   1024        setsr(oldsr);
   1025        setop(oldop);
   1026        setmode(oldmode);
   1027        setindex(oldindex);
   1028}
   1029
   1030static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
   1031{
   1032	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 
   1033	int x, x2, y2, old_dx, old_dy, vxres, vyres;
   1034	int height, width, line_ofs;
   1035	char __iomem *dst = NULL;
   1036	char __iomem *src = NULL;
   1037
   1038	vxres = info->var.xres_virtual;
   1039	vyres = info->var.yres_virtual;
   1040
   1041	if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
   1042	    area->sy > vyres)
   1043		return;
   1044
   1045	/* clip the destination */
   1046	old_dx = area->dx;
   1047	old_dy = area->dy;
   1048
   1049	/*
   1050	 * We could use hardware clipping but on many cards you get around
   1051	 * hardware clipping by writing to framebuffer directly.
   1052	 */
   1053	x2 = area->dx + area->width;
   1054	y2 = area->dy + area->height;
   1055	dx = area->dx > 0 ? area->dx : 0;
   1056	dy = area->dy > 0 ? area->dy : 0;
   1057	x2 = x2 < vxres ? x2 : vxres;
   1058	y2 = y2 < vyres ? y2 : vyres;
   1059	width = x2 - dx;
   1060	height = y2 - dy;
   1061
   1062	if (sx + dx < old_dx || sy + dy < old_dy)
   1063		return;
   1064
   1065	/* update sx1,sy1 */
   1066	sx += (dx - old_dx);
   1067	sy += (dy - old_dy);
   1068
   1069	/* the source must be completely inside the virtual screen */
   1070	if (sx + width > vxres || sy + height > vyres)
   1071		return;
   1072
   1073	switch (info->fix.type) {
   1074	case FB_TYPE_VGA_PLANES:
   1075		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
   1076			width = width/8;
   1077			line_ofs = info->fix.line_length - width;
   1078
   1079			setmode(1);
   1080			setop(0);
   1081			setsr(0xf);
   1082
   1083			if (dy < sy || (dy == sy && dx < sx)) {
   1084				dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
   1085				src = info->screen_base + (sx/8) + sy * info->fix.line_length;
   1086				while (height--) {
   1087					for (x = 0; x < width; x++) {
   1088						readb(src);
   1089						writeb(0, dst);
   1090						dst++;
   1091						src++;
   1092					}
   1093					src += line_ofs;
   1094					dst += line_ofs;
   1095				}
   1096			} else {
   1097				dst = info->screen_base + (dx/8) + width + 
   1098					(dy + height - 1) * info->fix.line_length;
   1099				src = info->screen_base + (sx/8) + width + 
   1100					(sy + height  - 1) * info->fix.line_length;
   1101				while (height--) {
   1102					for (x = 0; x < width; x++) {
   1103						dst--;
   1104						src--;
   1105						readb(src);
   1106						writeb(0, dst);
   1107					}
   1108					src -= line_ofs;
   1109					dst -= line_ofs;
   1110				}
   1111			}
   1112		} else 
   1113			vga_8planes_copyarea(info, area);
   1114		break;
   1115	case FB_TYPE_PACKED_PIXELS:
   1116	default:
   1117		cfb_copyarea(info, area);
   1118		break;
   1119	}
   1120}
   1121
   1122#define TRANS_MASK_LOW  {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
   1123#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
   1124			 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
   1125
   1126#if defined(__LITTLE_ENDIAN)
   1127static const u16 transl_l[] = TRANS_MASK_LOW;
   1128static const u16 transl_h[] = TRANS_MASK_HIGH;
   1129#elif defined(__BIG_ENDIAN)
   1130static const u16 transl_l[] = TRANS_MASK_HIGH;
   1131static const u16 transl_h[] = TRANS_MASK_LOW;
   1132#else
   1133#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
   1134#endif
   1135
   1136static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
   1137{
   1138        char oldindex = getindex();
   1139        char oldmode = setmode(0x40);
   1140        char oldop = setop(0);
   1141        char oldsr = setsr(0);
   1142        char oldmask = selectmask();
   1143	const unsigned char *cdat = image->data;
   1144	u32 dx = image->dx;
   1145        char __iomem *where;
   1146        int y;
   1147
   1148        dx /= 4;
   1149        where = info->screen_base + dx + image->dy * info->fix.line_length;
   1150
   1151        setmask(0xff);
   1152        writeb(image->bg_color, where);
   1153        readb(where);
   1154        selectmask();
   1155        setmask(image->fg_color ^ image->bg_color);
   1156        setmode(0x42);
   1157        setop(0x18);
   1158        for (y = 0; y < image->height; y++, where += info->fix.line_length)
   1159                writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
   1160        setmask(oldmask);
   1161        setsr(oldsr);
   1162        setop(oldop);
   1163        setmode(oldmode);
   1164        setindex(oldindex);
   1165}
   1166
   1167static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
   1168{
   1169	char __iomem *where = info->screen_base + (image->dx/8) +
   1170		image->dy * info->fix.line_length;
   1171	struct vga16fb_par *par = info->par;
   1172	char *cdat = (char *) image->data;
   1173	char __iomem *dst;
   1174	int x, y;
   1175
   1176	switch (info->fix.type) {
   1177	case FB_TYPE_VGA_PLANES:
   1178		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
   1179			if (par->isVGA) {
   1180				setmode(2);
   1181				setop(0);
   1182				setsr(0xf);
   1183				setcolor(image->fg_color);
   1184				selectmask();
   1185				
   1186				setmask(0xff);
   1187				writeb(image->bg_color, where);
   1188				rmb();
   1189				readb(where); /* fill latches */
   1190				setmode(3);
   1191				wmb();
   1192				for (y = 0; y < image->height; y++) {
   1193					dst = where;
   1194					for (x = image->width/8; x--;) 
   1195						writeb(*cdat++, dst++);
   1196					where += info->fix.line_length;
   1197				}
   1198				wmb();
   1199			} else {
   1200				setmode(0);
   1201				setop(0);
   1202				setsr(0xf);
   1203				setcolor(image->bg_color);
   1204				selectmask();
   1205				
   1206				setmask(0xff);
   1207				for (y = 0; y < image->height; y++) {
   1208					dst = where;
   1209					for (x=image->width/8; x--;){
   1210						rmw(dst);
   1211						setcolor(image->fg_color);
   1212						selectmask();
   1213						if (*cdat) {
   1214							setmask(*cdat++);
   1215							rmw(dst++);
   1216						}
   1217					}
   1218					where += info->fix.line_length;
   1219				}
   1220			}
   1221		} else 
   1222			vga_8planes_imageblit(info, image);
   1223		break;
   1224	case FB_TYPE_PACKED_PIXELS:
   1225	default:
   1226		cfb_imageblit(info, image);
   1227		break;
   1228	}
   1229}
   1230
   1231static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
   1232{
   1233	/*
   1234	 * Draw logo 
   1235	 */
   1236	struct vga16fb_par *par = info->par;
   1237	char __iomem *where =
   1238		info->screen_base + image->dy * info->fix.line_length +
   1239		image->dx/8;
   1240	const char *cdat = image->data;
   1241	char __iomem *dst;
   1242	int x, y;
   1243
   1244	switch (info->fix.type) {
   1245	case FB_TYPE_VGA_PLANES:
   1246		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
   1247		    par->isVGA) {
   1248			setsr(0xf);
   1249			setop(0);
   1250			setmode(0);
   1251			
   1252			for (y = 0; y < image->height; y++) {
   1253				for (x = 0; x < image->width; x++) {
   1254					dst = where + x/8;
   1255
   1256					setcolor(*cdat);
   1257					selectmask();
   1258					setmask(1 << (7 - (x % 8)));
   1259					fb_readb(dst);
   1260					fb_writeb(0, dst);
   1261
   1262					cdat++;
   1263				}
   1264				where += info->fix.line_length;
   1265			}
   1266		}
   1267		break;
   1268	case FB_TYPE_PACKED_PIXELS:
   1269		cfb_imageblit(info, image);
   1270		break;
   1271	default:
   1272		break;
   1273	}
   1274}
   1275				
   1276static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
   1277{
   1278	if (image->depth == 1)
   1279		vga_imageblit_expand(info, image);
   1280	else
   1281		vga_imageblit_color(info, image);
   1282}
   1283
   1284static void vga16fb_destroy(struct fb_info *info)
   1285{
   1286	iounmap(info->screen_base);
   1287	fb_dealloc_cmap(&info->cmap);
   1288	/* XXX unshare VGA regions */
   1289	framebuffer_release(info);
   1290}
   1291
   1292static const struct fb_ops vga16fb_ops = {
   1293	.owner		= THIS_MODULE,
   1294	.fb_open        = vga16fb_open,
   1295	.fb_release     = vga16fb_release,
   1296	.fb_destroy	= vga16fb_destroy,
   1297	.fb_check_var	= vga16fb_check_var,
   1298	.fb_set_par	= vga16fb_set_par,
   1299	.fb_setcolreg 	= vga16fb_setcolreg,
   1300	.fb_pan_display = vga16fb_pan_display,
   1301	.fb_blank 	= vga16fb_blank,
   1302	.fb_fillrect	= vga16fb_fillrect,
   1303	.fb_copyarea	= vga16fb_copyarea,
   1304	.fb_imageblit	= vga16fb_imageblit,
   1305};
   1306
   1307#ifndef MODULE
   1308static int __init vga16fb_setup(char *options)
   1309{
   1310	char *this_opt;
   1311	
   1312	if (!options || !*options)
   1313		return 0;
   1314	
   1315	while ((this_opt = strsep(&options, ",")) != NULL) {
   1316		if (!*this_opt) continue;
   1317	}
   1318	return 0;
   1319}
   1320#endif
   1321
   1322static int vga16fb_probe(struct platform_device *dev)
   1323{
   1324	struct fb_info *info;
   1325	struct vga16fb_par *par;
   1326	int i;
   1327	int ret = 0;
   1328
   1329	printk(KERN_DEBUG "vga16fb: initializing\n");
   1330	info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
   1331
   1332	if (!info) {
   1333		ret = -ENOMEM;
   1334		goto err_fb_alloc;
   1335	}
   1336	info->apertures = alloc_apertures(1);
   1337	if (!info->apertures) {
   1338		ret = -ENOMEM;
   1339		goto err_ioremap;
   1340	}
   1341
   1342	/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
   1343	info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
   1344
   1345	if (!info->screen_base) {
   1346		printk(KERN_ERR "vga16fb: unable to map device\n");
   1347		ret = -ENOMEM;
   1348		goto err_ioremap;
   1349	}
   1350
   1351	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
   1352	par = info->par;
   1353
   1354#if defined(CONFIG_X86)
   1355	par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC;
   1356#else
   1357	/* non-x86 architectures treat orig_video_isVGA as a boolean flag */
   1358	par->isVGA = screen_info.orig_video_isVGA;
   1359#endif
   1360	par->palette_blanked = 0;
   1361	par->vesa_blanked = 0;
   1362
   1363	i = par->isVGA? 6 : 2;
   1364	
   1365	vga16fb_defined.red.length   = i;
   1366	vga16fb_defined.green.length = i;
   1367	vga16fb_defined.blue.length  = i;	
   1368
   1369	/* name should not depend on EGA/VGA */
   1370	info->fbops = &vga16fb_ops;
   1371	info->var = vga16fb_defined;
   1372	info->fix = vga16fb_fix;
   1373	/* supports rectangles with widths of multiples of 8 */
   1374	info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
   1375	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
   1376		FBINFO_HWACCEL_YPAN;
   1377
   1378	i = (info->var.bits_per_pixel == 8) ? 256 : 16;
   1379	ret = fb_alloc_cmap(&info->cmap, i, 0);
   1380	if (ret) {
   1381		printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
   1382		ret = -ENOMEM;
   1383		goto err_alloc_cmap;
   1384	}
   1385
   1386	if (vga16fb_check_var(&info->var, info)) {
   1387		printk(KERN_ERR "vga16fb: unable to validate variable\n");
   1388		ret = -EINVAL;
   1389		goto err_check_var;
   1390	}
   1391
   1392	vga16fb_update_fix(info);
   1393
   1394	info->apertures->ranges[0].base = VGA_FB_PHYS;
   1395	info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
   1396
   1397	if (register_framebuffer(info) < 0) {
   1398		printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
   1399		ret = -EINVAL;
   1400		goto err_check_var;
   1401	}
   1402
   1403	fb_info(info, "%s frame buffer device\n", info->fix.id);
   1404	platform_set_drvdata(dev, info);
   1405
   1406	return 0;
   1407
   1408 err_check_var:
   1409	fb_dealloc_cmap(&info->cmap);
   1410 err_alloc_cmap:
   1411	iounmap(info->screen_base);
   1412 err_ioremap:
   1413	framebuffer_release(info);
   1414 err_fb_alloc:
   1415	return ret;
   1416}
   1417
   1418static int vga16fb_remove(struct platform_device *dev)
   1419{
   1420	struct fb_info *info = platform_get_drvdata(dev);
   1421
   1422	if (info)
   1423		unregister_framebuffer(info);
   1424
   1425	return 0;
   1426}
   1427
   1428static struct platform_driver vga16fb_driver = {
   1429	.probe = vga16fb_probe,
   1430	.remove = vga16fb_remove,
   1431	.driver = {
   1432		.name = "vga16fb",
   1433	},
   1434};
   1435
   1436static struct platform_device *vga16fb_device;
   1437
   1438static int __init vga16fb_init(void)
   1439{
   1440	int ret;
   1441#ifndef MODULE
   1442	char *option = NULL;
   1443
   1444	if (fb_get_options("vga16fb", &option))
   1445		return -ENODEV;
   1446
   1447	vga16fb_setup(option);
   1448#endif
   1449
   1450	ret = check_mode_supported();
   1451	if (ret)
   1452		return ret;
   1453
   1454	ret = platform_driver_register(&vga16fb_driver);
   1455
   1456	if (!ret) {
   1457		vga16fb_device = platform_device_alloc("vga16fb", 0);
   1458
   1459		if (vga16fb_device)
   1460			ret = platform_device_add(vga16fb_device);
   1461		else
   1462			ret = -ENOMEM;
   1463
   1464		if (ret) {
   1465			platform_device_put(vga16fb_device);
   1466			platform_driver_unregister(&vga16fb_driver);
   1467		}
   1468	}
   1469
   1470	return ret;
   1471}
   1472
   1473static void __exit vga16fb_exit(void)
   1474{
   1475	platform_device_unregister(vga16fb_device);
   1476	platform_driver_unregister(&vga16fb_driver);
   1477}
   1478
   1479MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
   1480MODULE_LICENSE("GPL");
   1481module_init(vga16fb_init);
   1482module_exit(vga16fb_exit);