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