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