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