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