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