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