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 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/mm.h>
17 #include <linux/tty.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
20 #include <linux/fb.h>
21 #include <linux/console.h>
22 #include <linux/selection.h>
23 #include <linux/ioport.h>
24 #include <linux/init.h>
25 
26 #include <asm/io.h>
27 
28 #include <video/fbcon.h>
29 #include <video/fbcon-vga-planes.h>
30 #include "vga.h"
31 
32 #define dac_reg	(0x3c8)
33 #define dac_val	(0x3c9)
34 
35 #define VGA_FB_PHYS 0xA0000
36 #define VGA_FB_PHYS_LEN 65536
37 
38 /* --------------------------------------------------------------------- */
39 
40 /*
41  * card parameters
42  */
43 
44 static struct vga16fb_info {
45 	struct fb_info  fb_info;
46 	char *video_vbase;			/* 0xa0000 map address */
47 	int isVGA;
48 
49 	/* structure holding original VGA register settings when the
50            screen is blanked */
51 	struct {
52 		unsigned char	SeqCtrlIndex;		/* Sequencer Index reg.   */
53 		unsigned char	CrtCtrlIndex;		/* CRT-Contr. Index reg.  */
54 		unsigned char	CrtMiscIO;		/* Miscellaneous register */
55 		unsigned char	HorizontalTotal;	/* CRT-Controller:00h */
56 		unsigned char	HorizDisplayEnd;	/* CRT-Controller:01h */
57 		unsigned char	StartHorizRetrace;	/* CRT-Controller:04h */
58 		unsigned char	EndHorizRetrace;	/* CRT-Controller:05h */
59 		unsigned char	Overflow;		/* CRT-Controller:07h */
60 		unsigned char	StartVertRetrace;	/* CRT-Controller:10h */
61 		unsigned char	EndVertRetrace;		/* CRT-Controller:11h */
62 		unsigned char	ModeControl;		/* CRT-Controller:17h */
63 		unsigned char	ClockingMode;		/* Seq-Controller:01h */
64 	} vga_state;
65 
66 	int palette_blanked;
67 	int vesa_blanked;
68 } vga16fb;
69 
70 
71 struct vga16fb_par {
72 	u8 crtc[VGA_CRT_C];
73 	u8 atc[VGA_ATT_C];
74 	u8 gdc[VGA_GFX_C];
75 	u8 seq[VGA_SEQ_C];
76 	u8 misc;
77 	u8 vss;
78 	struct fb_var_screeninfo var;
79 };
80 
81 /* --------------------------------------------------------------------- */
82 
83 static struct fb_var_screeninfo vga16fb_defined = {
84 	640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
85 	0,0,		/* virtual -> visible no offset */
86 	4,		/* depth -> load bits_per_pixel */
87 	0,		/* greyscale ? */
88 	{0,0,0},	/* R */
89 	{0,0,0},	/* G */
90 	{0,0,0},	/* B */
91 	{0,0,0},	/* transparency */
92 	0,		/* standard pixel format */
93 	FB_ACTIVATE_NOW,
94 	-1,-1,
95 	0,
96 	39721, 48, 16, 39, 8,
97 	96, 2, 0,	/* No sync info */
98 	FB_VMODE_NONINTERLACED,
99 	{0,0,0,0,0,0}
100 };
101 
102 static struct display disp;
103 static struct { u_short blue, green, red, pad; } palette[256];
104 
105 static int             currcon   = 0;
106 
107 /* --------------------------------------------------------------------- */
108 
vga16fb_pan_var(struct fb_info * info,struct fb_var_screeninfo * var)109 static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var)
110 {
111 	u32 pos = (var->xres_virtual * var->yoffset + var->xoffset) >> 3;
112 	outb(VGA_CRTC_START_HI, VGA_CRT_IC);
113 	outb(pos >> 8, VGA_CRT_DC);
114 	outb(VGA_CRTC_START_LO, VGA_CRT_IC);
115 	outb(pos & 0xFF, VGA_CRT_DC);
116 #if 0
117 	/* if someone supports xoffset in bit resolution */
118 	inb(VGA_IS1_RC);		/* reset flip-flop */
119 	outb(VGA_ATC_PEL, VGA_ATT_IW);
120 	outb(xoffset & 7, VGA_ATT_IW);
121 	inb(VGA_IS1_RC);
122 	outb(0x20, VGA_ATT_IW);
123 #endif
124 }
125 
vga16fb_update_var(int con,struct fb_info * info)126 static int vga16fb_update_var(int con, struct fb_info *info)
127 {
128 	vga16fb_pan_var(info, &fb_display[con].var);
129 	return 0;
130 }
131 
vga16fb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)132 static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con,
133 			   struct fb_info *info)
134 {
135 	struct display *p;
136 
137 	if (con < 0)
138 		p = &disp;
139 	else
140 		p = fb_display + con;
141 
142 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
143 	strcpy(fix->id,"VGA16 VGA");
144 
145 	fix->smem_start = VGA_FB_PHYS;
146 	fix->smem_len = VGA_FB_PHYS_LEN;
147 	fix->type = FB_TYPE_VGA_PLANES;
148 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
149 	fix->xpanstep  = 8;
150 	fix->ypanstep  = 1;
151 	fix->ywrapstep = 0;
152 	fix->line_length = p->var.xres_virtual / 8;
153 	return 0;
154 }
155 
vga16fb_get_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)156 static int vga16fb_get_var(struct fb_var_screeninfo *var, int con,
157 			 struct fb_info *info)
158 {
159 	if(con==-1)
160 		memcpy(var, &vga16fb_defined, sizeof(struct fb_var_screeninfo));
161 	else
162 		*var=fb_display[con].var;
163 	return 0;
164 }
165 
vga16fb_set_disp(int con,struct vga16fb_info * info)166 static void vga16fb_set_disp(int con, struct vga16fb_info *info)
167 {
168 	struct fb_fix_screeninfo fix;
169 	struct display *display;
170 
171 	if (con < 0)
172 		display = &disp;
173 	else
174 		display = fb_display + con;
175 
176 
177 	vga16fb_get_fix(&fix, con, &info->fb_info);
178 
179 	display->screen_base = info->video_vbase;
180 	display->visual = fix.visual;
181 	display->type = fix.type;
182 	display->type_aux = fix.type_aux;
183 	display->ypanstep = fix.ypanstep;
184 	display->ywrapstep = fix.ywrapstep;
185 	display->line_length = fix.line_length;
186 	display->next_line = fix.line_length;
187 	display->can_soft_blank = 1;
188 	display->inverse = 0;
189 
190 	if (info->isVGA)
191 		display->dispsw = &fbcon_vga_planes;
192 	else
193 		display->dispsw = &fbcon_ega_planes;
194 	display->scrollmode = SCROLL_YREDRAW;
195 }
196 
vga16fb_encode_var(struct fb_var_screeninfo * var,const struct vga16fb_par * par,const struct vga16fb_info * info)197 static void vga16fb_encode_var(struct fb_var_screeninfo *var,
198 			       const struct vga16fb_par *par,
199 			       const struct vga16fb_info *info)
200 {
201 	*var = par->var;
202 }
203 
vga16fb_clock_chip(struct vga16fb_par * par,unsigned int pixclock,const struct vga16fb_info * info)204 static void vga16fb_clock_chip(struct vga16fb_par *par,
205 			       unsigned int pixclock,
206 			       const struct vga16fb_info *info)
207 {
208 	static struct {
209 		u32 pixclock;
210 		u8  misc;
211 		u8  seq_clock_mode;
212 	} *ptr, *best, vgaclocks[] = {
213 		{ 79442 /* 12.587 */, 0x00, 0x08},
214 		{ 70616 /* 14.161 */, 0x04, 0x08},
215 		{ 39721 /* 25.175 */, 0x00, 0x00},
216 		{ 35308 /* 28.322 */, 0x04, 0x00},
217 		{     0 /* bad */,    0x00, 0x00}};
218 	int err;
219 
220 	best = vgaclocks;
221 	err = pixclock - best->pixclock;
222 	if (err < 0) err = -err;
223 	for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
224 		int tmp;
225 
226 		tmp = pixclock - ptr->pixclock;
227 		if (tmp < 0) tmp = -tmp;
228 		if (tmp < err) {
229 			err = tmp;
230 			best = ptr;
231 		}
232 	}
233 	par->misc |= best->misc;
234 	par->seq[VGA_SEQ_CLOCK_MODE] |= best->seq_clock_mode;
235 	par->var.pixclock = best->pixclock;
236 }
237 
238 #define FAIL(X) return -EINVAL
239 
vga16fb_decode_var(const struct fb_var_screeninfo * var,struct vga16fb_par * par,const struct vga16fb_info * info)240 static int vga16fb_decode_var(const struct fb_var_screeninfo *var,
241 			      struct vga16fb_par *par,
242 			      const struct vga16fb_info *info)
243 {
244 	u32 xres, right, hslen, left, xtotal;
245 	u32 yres, lower, vslen, upper, ytotal;
246 	u32 vxres, xoffset, vyres, yoffset;
247 	u32 pos;
248 	u8 r7, rMode;
249 	int i;
250 
251 	if (var->bits_per_pixel != 4)
252 		return -EINVAL;
253 	xres = (var->xres + 7) & ~7;
254 	vxres = (var->xres_virtual + 0xF) & ~0xF;
255 	xoffset = (var->xoffset + 7) & ~7;
256 	left = (var->left_margin + 7) & ~7;
257 	right = (var->right_margin + 7) & ~7;
258 	hslen = (var->hsync_len + 7) & ~7;
259 
260 	if (vxres < xres)
261 		vxres = xres;
262 	if (xres + xoffset > vxres)
263 		xoffset = vxres - xres;
264 
265 	par->var.xres = xres;
266 	par->var.right_margin = right;
267 	par->var.hsync_len = hslen;
268 	par->var.left_margin = left;
269 	par->var.xres_virtual = vxres;
270 	par->var.xoffset = xoffset;
271 
272 	xres >>= 3;
273 	right >>= 3;
274 	hslen >>= 3;
275 	left >>= 3;
276 	vxres >>= 3;
277 	xtotal = xres + right + hslen + left;
278 	if (xtotal >= 256)
279 		FAIL("xtotal too big");
280 	if (hslen > 32)
281 		FAIL("hslen too big");
282 	if (right + hslen + left > 64)
283 		FAIL("hblank too big");
284 	par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
285 	par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
286 	par->crtc[VGA_CRTC_H_DISP] = xres - 1;
287 	pos = xres + right;
288 	par->crtc[VGA_CRTC_H_SYNC_START] = pos;
289 	pos += hslen;
290 	par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
291 	pos += left - 2; /* blank_end + 2 <= total + 5 */
292 	par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
293 	if (pos & 0x20)
294 		par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
295 
296 	yres = var->yres;
297 	lower = var->lower_margin;
298 	vslen = var->vsync_len;
299 	upper = var->upper_margin;
300 	vyres = var->yres_virtual;
301 	yoffset = var->yoffset;
302 
303 	if (yres > vyres)
304 		vyres = yres;
305 	if (vxres * vyres > 65536) {
306 		vyres = 65536 / vxres;
307 		if (vyres < yres)
308 			return -ENOMEM;
309 	}
310 	if (yoffset + yres > vyres)
311 		yoffset = vyres - yres;
312 	par->var.yres = yres;
313 	par->var.lower_margin = lower;
314 	par->var.vsync_len = vslen;
315 	par->var.upper_margin = upper;
316 	par->var.yres_virtual = vyres;
317 	par->var.yoffset = yoffset;
318 
319 	if (var->vmode & FB_VMODE_DOUBLE) {
320 		yres <<= 1;
321 		lower <<= 1;
322 		vslen <<= 1;
323 		upper <<= 1;
324 	}
325 	ytotal = yres + lower + vslen + upper;
326 	if (ytotal > 1024) {
327 		ytotal >>= 1;
328 		yres >>= 1;
329 		lower >>= 1;
330 		vslen >>= 1;
331 		upper >>= 1;
332 		rMode = 0x04;
333 	} else
334 		rMode = 0x00;
335 	if (ytotal > 1024)
336 		FAIL("ytotal too big");
337 	if (vslen > 16)
338 		FAIL("vslen too big");
339 	par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
340 	r7 = 0x10;	/* disable linecompare */
341 	if (ytotal & 0x100) r7 |= 0x01;
342 	if (ytotal & 0x200) r7 |= 0x20;
343 	par->crtc[VGA_CRTC_PRESET_ROW] = 0;
344 	par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;	/* 1 scanline, no linecmp */
345 	par->var.vmode = var->vmode;
346 	if (var->vmode & FB_VMODE_DOUBLE)
347 		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
348 	par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
349 	par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
350 	pos = yoffset * vxres + (xoffset >> 3);
351 	par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
352 	par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
353 	par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
354 	par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
355 	pos = yres - 1;
356 	par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
357 	par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
358 	if (pos & 0x100)
359 		r7 |= 0x0A;	/* 0x02 -> DISP_END, 0x08 -> BLANK_START */
360 	if (pos & 0x200) {
361 		r7 |= 0x40;	/* 0x40 -> DISP_END */
362 		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
363 	}
364 	pos += lower;
365 	par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
366 	if (pos & 0x100)
367 		r7 |= 0x04;
368 	if (pos & 0x200)
369 		r7 |= 0x80;
370 	pos += vslen;
371 	par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
372 	pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
373 	par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
374                      but some SVGA chips requires all 8 bits to set */
375 	if (vxres >= 512)
376 		FAIL("vxres too long");
377 	par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
378 	par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;
379 	par->crtc[VGA_CRTC_MODE] = rMode | 0xE3;
380 	par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
381 	par->crtc[VGA_CRTC_OVERFLOW] = r7;
382 
383 	par->vss = 0x00;	/* 3DA */
384 
385 	for (i = 0x00; i < 0x10; i++)
386 		par->atc[i] = i;
387 	par->atc[VGA_ATC_MODE] = 0x81;
388 	par->atc[VGA_ATC_OVERSCAN] = 0x00;	/* 0 for EGA, 0xFF for VGA */
389 	par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
390 	par->atc[VGA_ATC_PEL] = xoffset & 7;
391 	par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
392 
393 	par->misc = 0xC3;	/* enable CPU, ports 0x3Dx, positive sync */
394 	par->var.sync = var->sync;
395 	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
396 		par->misc &= ~0x40;
397 	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
398 		par->misc &= ~0x80;
399 
400 	par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
401 	par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
402 	par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
403 	par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
404 
405 	par->gdc[VGA_GFX_SR_VALUE] = 0x00;
406 	par->gdc[VGA_GFX_SR_ENABLE] = 0x0F;
407 	par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
408 	par->gdc[VGA_GFX_DATA_ROTATE] = 0x20;
409 	par->gdc[VGA_GFX_PLANE_READ] = 0;
410 	par->gdc[VGA_GFX_MODE] = 0x00;
411 	par->gdc[VGA_GFX_MISC] = 0x05;
412 	par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
413 	par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
414 
415 	vga16fb_clock_chip(par, var->pixclock, info);
416 
417 	par->var.bits_per_pixel = 4;
418 	par->var.grayscale = var->grayscale;
419 	par->var.red.offset = par->var.green.offset = par->var.blue.offset =
420 	par->var.transp.offset = 0;
421 	par->var.red.length = par->var.green.length = par->var.blue.length =
422 		(info->isVGA) ? 6 : 2;
423 	par->var.transp.length = 0;
424 	par->var.nonstd = 0;
425 	par->var.activate = FB_ACTIVATE_NOW;
426 	par->var.height = -1;
427 	par->var.width = -1;
428 	par->var.accel_flags = 0;
429 
430 	return 0;
431 }
432 #undef FAIL
433 
vga16fb_set_par(const struct vga16fb_par * par,struct vga16fb_info * info)434 static int vga16fb_set_par(const struct vga16fb_par *par,
435 			   struct vga16fb_info *info)
436 {
437 	int i;
438 
439 	outb(inb(VGA_MIS_R) | 0x01, VGA_MIS_W);
440 
441 	/* Enable graphics register modification */
442 	if (!info->isVGA) {
443 		outb(0x00, EGA_GFX_E0);
444 		outb(0x01, EGA_GFX_E1);
445 	}
446 
447 	/* update misc output register */
448 	outb(par->misc, VGA_MIS_W);
449 
450 	/* synchronous reset on */
451 	outb(0x00, VGA_SEQ_I);
452 	outb(0x01, VGA_SEQ_D);
453 
454 	/* write sequencer registers */
455 	outb(1, VGA_SEQ_I);
456 	outb(par->seq[1] | 0x20, VGA_SEQ_D);
457 	for (i = 2; i < VGA_SEQ_C; i++) {
458 		outb(i, VGA_SEQ_I);
459 		outb(par->seq[i], VGA_SEQ_D);
460 	}
461 
462 	/* synchronous reset off */
463 	outb(0x00, VGA_SEQ_I);
464 	outb(0x03, VGA_SEQ_D);
465 
466 	/* deprotect CRT registers 0-7 */
467 	outb(0x11, VGA_CRT_IC);
468 	outb(par->crtc[0x11], VGA_CRT_DC);
469 
470 	/* write CRT registers */
471 	for (i = 0; i < VGA_CRT_C; i++) {
472 		outb(i, VGA_CRT_IC);
473 		outb(par->crtc[i], VGA_CRT_DC);
474 	}
475 
476 	/* write graphics controller registers */
477 	for (i = 0; i < VGA_GFX_C; i++) {
478 		outb(i, VGA_GFX_I);
479 		outb(par->gdc[i], VGA_GFX_D);
480 	}
481 
482 	/* write attribute controller registers */
483 	for (i = 0; i < VGA_ATT_C; i++) {
484 		inb_p(VGA_IS1_RC);		/* reset flip-flop */
485 		outb_p(i, VGA_ATT_IW);
486 		outb_p(par->atc[i], VGA_ATT_IW);
487 	}
488 
489 	/* Wait for screen to stabilize. */
490 	mdelay(50);
491 
492 	outb(0x01, VGA_SEQ_I);
493 	outb(par->seq[1], VGA_SEQ_D);
494 
495 	inb(VGA_IS1_RC);
496 	outb(0x20, VGA_ATT_IW);
497 
498 	return 0;
499 }
500 
vga16fb_set_var(struct fb_var_screeninfo * var,int con,struct fb_info * fb)501 static int vga16fb_set_var(struct fb_var_screeninfo *var, int con,
502 			  struct fb_info *fb)
503 {
504 	struct vga16fb_info *info = (struct vga16fb_info*)fb;
505 	struct vga16fb_par par;
506 	struct display *display;
507 	int err;
508 
509 	if (con < 0)
510 		display = fb->disp;
511 	else
512 		display = fb_display + con;
513 	if ((err = vga16fb_decode_var(var, &par, info)) != 0)
514 		return err;
515 	vga16fb_encode_var(var, &par, info);
516 
517 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
518 		return 0;
519 
520 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
521 		u32 oldxres, oldyres, oldvxres, oldvyres, oldbpp;
522 
523 		oldxres = display->var.xres;
524 		oldyres = display->var.yres;
525 		oldvxres = display->var.xres_virtual;
526 		oldvyres = display->var.yres_virtual;
527 		oldbpp = display->var.bits_per_pixel;
528 
529 		display->var = *var;
530 
531 		if (oldxres != var->xres || oldyres != var->yres ||
532 		    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
533 		    oldbpp != var->bits_per_pixel) {
534 			vga16fb_set_disp(con, info);
535 			if (info->fb_info.changevar)
536 				info->fb_info.changevar(con);
537 		}
538 		if (con == currcon)
539 			vga16fb_set_par(&par, info);
540 	}
541 
542 	return 0;
543 }
544 
ega16_setpalette(int regno,unsigned red,unsigned green,unsigned blue)545 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
546 {
547 	static unsigned char map[] = { 000, 001, 010, 011 };
548 	int val;
549 
550 	val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
551 	inb_p(0x3DA);   /* ! 0x3BA */
552 	outb_p(regno, 0x3C0);
553 	outb_p(val, 0x3C0);
554 	inb_p(0x3DA);   /* some clones need it */
555 	outb_p(0x20, 0x3C0); /* unblank screen */
556 }
557 
vga16_getcolreg(unsigned regno,unsigned * red,unsigned * green,unsigned * blue,unsigned * transp,struct fb_info * fb_info)558 static int vga16_getcolreg(unsigned regno, unsigned *red, unsigned *green,
559 			  unsigned *blue, unsigned *transp,
560 			  struct fb_info *fb_info)
561 {
562 	/*
563 	 *  Read a single color register and split it into colors/transparent.
564 	 *  Return != 0 for invalid regno.
565 	 */
566 
567 	if (regno >= 16)
568 		return 1;
569 
570 	*red   = palette[regno].red;
571 	*green = palette[regno].green;
572 	*blue  = palette[regno].blue;
573 	*transp = 0;
574 	return 0;
575 }
576 
vga16_setpalette(int regno,unsigned red,unsigned green,unsigned blue)577 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
578 {
579 	outb(regno,       dac_reg);
580 	outb(red   >> 10, dac_val);
581 	outb(green >> 10, dac_val);
582 	outb(blue  >> 10, dac_val);
583 }
584 
vga16_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * fb_info)585 static int vga16_setcolreg(unsigned regno, unsigned red, unsigned green,
586 			  unsigned blue, unsigned transp,
587 			  struct fb_info *fb_info)
588 {
589 	int gray;
590 
591 	/*
592 	 *  Set a single color register. The values supplied are
593 	 *  already rounded down to the hardware's capabilities
594 	 *  (according to the entries in the `var' structure). Return
595 	 *  != 0 for invalid regno.
596 	 */
597 
598 	if (regno >= 16)
599 		return 1;
600 
601 	palette[regno].red   = red;
602 	palette[regno].green = green;
603 	palette[regno].blue  = blue;
604 
605 	if (currcon < 0)
606 		gray = disp.var.grayscale;
607 	else
608 		gray = fb_display[currcon].var.grayscale;
609 	if (gray) {
610 		/* gray = 0.30*R + 0.59*G + 0.11*B */
611 		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
612 	}
613 	if (((struct vga16fb_info *) fb_info)->isVGA)
614 		vga16_setpalette(regno,red,green,blue);
615 	else
616 		ega16_setpalette(regno,red,green,blue);
617 
618 	return 0;
619 }
620 
do_install_cmap(int con,struct fb_info * info)621 static void do_install_cmap(int con, struct fb_info *info)
622 {
623 	if (con != currcon)
624 		return;
625 	if (fb_display[con].cmap.len)
626 		fb_set_cmap(&fb_display[con].cmap, 1, vga16_setcolreg, info);
627 	else
628 		fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg,
629 			    info);
630 }
631 
vga16fb_get_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)632 static int vga16fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
633 			   struct fb_info *info)
634 {
635 	if (con == currcon) /* current console? */
636 		return fb_get_cmap(cmap, kspc, vga16_getcolreg, info);
637 	else if (fb_display[con].cmap.len) /* non default colormap? */
638 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
639 	else
640 		fb_copy_cmap(fb_default_cmap(16),
641 		     cmap, kspc ? 0 : 2);
642 	return 0;
643 }
644 
vga16fb_set_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)645 static int vga16fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
646 			   struct fb_info *info)
647 {
648 	int err;
649 
650 	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
651 		err = fb_alloc_cmap(&fb_display[con].cmap,16,0);
652 		if (err)
653 			return err;
654 	}
655 	if (con == currcon)			/* current console? */
656 		return fb_set_cmap(cmap, kspc, vga16_setcolreg, info);
657 	else
658 		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
659 	return 0;
660 }
661 
vga16fb_pan_display(struct fb_var_screeninfo * var,int con,struct fb_info * info)662 static int vga16fb_pan_display(struct fb_var_screeninfo *var, int con,
663 			       struct fb_info *info)
664 {
665 	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
666 	    var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
667 		return -EINVAL;
668 	if (con == currcon)
669 		vga16fb_pan_var(info, var);
670 	fb_display[con].var.xoffset = var->xoffset;
671 	fb_display[con].var.yoffset = var->yoffset;
672 	fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
673 	return 0;
674 }
675 
676 static struct fb_ops vga16fb_ops = {
677 	owner:		THIS_MODULE,
678 	fb_get_fix:	vga16fb_get_fix,
679 	fb_get_var:	vga16fb_get_var,
680 	fb_set_var:	vga16fb_set_var,
681 	fb_get_cmap:	vga16fb_get_cmap,
682 	fb_set_cmap:	vga16fb_set_cmap,
683 	fb_pan_display:	vga16fb_pan_display,
684 };
685 
vga16fb_setup(char * options)686 int vga16fb_setup(char *options)
687 {
688 	char *this_opt;
689 
690 	vga16fb.fb_info.fontname[0] = '\0';
691 
692 	if (!options || !*options)
693 		return 0;
694 
695 	while ((this_opt = strsep(&options, ",")) != NULL) {
696 		if (!*this_opt) continue;
697 
698 		if (!strncmp(this_opt, "font:", 5))
699 			strcpy(vga16fb.fb_info.fontname, this_opt+5);
700 	}
701 	return 0;
702 }
703 
vga16fb_switch(int con,struct fb_info * fb)704 static int vga16fb_switch(int con, struct fb_info *fb)
705 {
706 	struct vga16fb_par par;
707 	struct vga16fb_info *info = (struct vga16fb_info*)fb;
708 
709 	/* Do we have to save the colormap? */
710 	if (fb_display[currcon].cmap.len)
711 		fb_get_cmap(&fb_display[currcon].cmap, 1, vga16_getcolreg,
712 			    fb);
713 
714 	currcon = con;
715 	vga16fb_decode_var(&fb_display[con].var, &par, info);
716 	vga16fb_set_par(&par, info);
717 	vga16fb_set_disp(con, info);
718 
719 	/* Install new colormap */
720 	do_install_cmap(con, fb);
721 /*	vga16fb_update_var(con, fb); */
722 	return 1;
723 }
724 
725 /* The following VESA blanking code is taken from vgacon.c.  The VGA
726    blanking code was originally by Huang shi chao, and modified by
727    Christoph Rimek (chrimek@toppoint.de) and todd j. derr
728    (tjd@barefoot.org) for Linux. */
729 #define attrib_port	0x3c0
730 #define seq_port_reg	0x3c4
731 #define seq_port_val	0x3c5
732 #define gr_port_reg	0x3ce
733 #define gr_port_val	0x3cf
734 #define video_misc_rd	0x3cc
735 #define video_misc_wr	0x3c2
736 #define vga_video_port_reg	0x3d4
737 #define vga_video_port_val	0x3d5
738 
vga_vesa_blank(struct vga16fb_info * info,int mode)739 static void vga_vesa_blank(struct vga16fb_info *info, int mode)
740 {
741 	unsigned char SeqCtrlIndex;
742 	unsigned char CrtCtrlIndex;
743 
744 	cli();
745 	SeqCtrlIndex = inb_p(seq_port_reg);
746 	CrtCtrlIndex = inb_p(vga_video_port_reg);
747 
748 	/* save original values of VGA controller registers */
749 	if(!info->vesa_blanked) {
750 		info->vga_state.CrtMiscIO = inb_p(video_misc_rd);
751 		sti();
752 
753 		outb_p(0x00,vga_video_port_reg);	/* HorizontalTotal */
754 		info->vga_state.HorizontalTotal = inb_p(vga_video_port_val);
755 		outb_p(0x01,vga_video_port_reg);	/* HorizDisplayEnd */
756 		info->vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
757 		outb_p(0x04,vga_video_port_reg);	/* StartHorizRetrace */
758 		info->vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
759 		outb_p(0x05,vga_video_port_reg);	/* EndHorizRetrace */
760 		info->vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
761 		outb_p(0x07,vga_video_port_reg);	/* Overflow */
762 		info->vga_state.Overflow = inb_p(vga_video_port_val);
763 		outb_p(0x10,vga_video_port_reg);	/* StartVertRetrace */
764 		info->vga_state.StartVertRetrace = inb_p(vga_video_port_val);
765 		outb_p(0x11,vga_video_port_reg);	/* EndVertRetrace */
766 		info->vga_state.EndVertRetrace = inb_p(vga_video_port_val);
767 		outb_p(0x17,vga_video_port_reg);	/* ModeControl */
768 		info->vga_state.ModeControl = inb_p(vga_video_port_val);
769 		outb_p(0x01,seq_port_reg);		/* ClockingMode */
770 		info->vga_state.ClockingMode = inb_p(seq_port_val);
771 	}
772 
773 	/* assure that video is enabled */
774 	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
775 	cli();
776 	outb_p(0x01,seq_port_reg);
777 	outb_p(info->vga_state.ClockingMode | 0x20,seq_port_val);
778 
779 	/* test for vertical retrace in process.... */
780 	if ((info->vga_state.CrtMiscIO & 0x80) == 0x80)
781 		outb_p(info->vga_state.CrtMiscIO & 0xef,video_misc_wr);
782 
783 	/*
784 	 * Set <End of vertical retrace> to minimum (0) and
785 	 * <Start of vertical Retrace> to maximum (incl. overflow)
786 	 * Result: turn off vertical sync (VSync) pulse.
787 	 */
788 	if (mode & VESA_VSYNC_SUSPEND) {
789 		outb_p(0x10,vga_video_port_reg);	/* StartVertRetrace */
790 		outb_p(0xff,vga_video_port_val); 	/* maximum value */
791 		outb_p(0x11,vga_video_port_reg);	/* EndVertRetrace */
792 		outb_p(0x40,vga_video_port_val);	/* minimum (bits 0..3)  */
793 		outb_p(0x07,vga_video_port_reg);	/* Overflow */
794 		outb_p(info->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
795 	}
796 
797 	if (mode & VESA_HSYNC_SUSPEND) {
798 		/*
799 		 * Set <End of horizontal retrace> to minimum (0) and
800 		 *  <Start of horizontal Retrace> to maximum
801 		 * Result: turn off horizontal sync (HSync) pulse.
802 		 */
803 		outb_p(0x04,vga_video_port_reg);	/* StartHorizRetrace */
804 		outb_p(0xff,vga_video_port_val);	/* maximum */
805 		outb_p(0x05,vga_video_port_reg);	/* EndHorizRetrace */
806 		outb_p(0x00,vga_video_port_val);	/* minimum (0) */
807 	}
808 
809 	/* restore both index registers */
810 	outb_p(SeqCtrlIndex,seq_port_reg);
811 	outb_p(CrtCtrlIndex,vga_video_port_reg);
812 	sti();
813 }
814 
vga_vesa_unblank(struct vga16fb_info * info)815 static void vga_vesa_unblank(struct vga16fb_info *info)
816 {
817 	unsigned char SeqCtrlIndex;
818 	unsigned char CrtCtrlIndex;
819 
820 	cli();
821 	SeqCtrlIndex = inb_p(seq_port_reg);
822 	CrtCtrlIndex = inb_p(vga_video_port_reg);
823 
824 	/* restore original values of VGA controller registers */
825 	outb_p(info->vga_state.CrtMiscIO,video_misc_wr);
826 
827 	outb_p(0x00,vga_video_port_reg);		/* HorizontalTotal */
828 	outb_p(info->vga_state.HorizontalTotal,vga_video_port_val);
829 	outb_p(0x01,vga_video_port_reg);		/* HorizDisplayEnd */
830 	outb_p(info->vga_state.HorizDisplayEnd,vga_video_port_val);
831 	outb_p(0x04,vga_video_port_reg);		/* StartHorizRetrace */
832 	outb_p(info->vga_state.StartHorizRetrace,vga_video_port_val);
833 	outb_p(0x05,vga_video_port_reg);		/* EndHorizRetrace */
834 	outb_p(info->vga_state.EndHorizRetrace,vga_video_port_val);
835 	outb_p(0x07,vga_video_port_reg);		/* Overflow */
836 	outb_p(info->vga_state.Overflow,vga_video_port_val);
837 	outb_p(0x10,vga_video_port_reg);		/* StartVertRetrace */
838 	outb_p(info->vga_state.StartVertRetrace,vga_video_port_val);
839 	outb_p(0x11,vga_video_port_reg);		/* EndVertRetrace */
840 	outb_p(info->vga_state.EndVertRetrace,vga_video_port_val);
841 	outb_p(0x17,vga_video_port_reg);		/* ModeControl */
842 	outb_p(info->vga_state.ModeControl,vga_video_port_val);
843 	outb_p(0x01,seq_port_reg);		/* ClockingMode */
844 	outb_p(info->vga_state.ClockingMode,seq_port_val);
845 
846 	/* restore index/control registers */
847 	outb_p(SeqCtrlIndex,seq_port_reg);
848 	outb_p(CrtCtrlIndex,vga_video_port_reg);
849 	sti();
850 }
851 
vga_pal_blank(void)852 static void vga_pal_blank(void)
853 {
854 	int i;
855 
856 	for (i=0; i<16; i++) {
857 		outb_p (i, dac_reg) ;
858 		outb_p (0, dac_val) ;
859 		outb_p (0, dac_val) ;
860 		outb_p (0, dac_val) ;
861 	}
862 }
863 
864 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
vga16fb_blank(int blank,struct fb_info * fb_info)865 static void vga16fb_blank(int blank, struct fb_info *fb_info)
866 {
867 	struct vga16fb_info *info = (struct vga16fb_info*)fb_info;
868 
869 	switch (blank) {
870 	case 0:				/* Unblank */
871 		if (info->vesa_blanked) {
872 			vga_vesa_unblank(info);
873 			info->vesa_blanked = 0;
874 		}
875 		if (info->palette_blanked) {
876 			do_install_cmap(currcon, fb_info);
877 			info->palette_blanked = 0;
878 		}
879 		break;
880 	case 1:				/* blank */
881 		vga_pal_blank();
882 		info->palette_blanked = 1;
883 		break;
884 	default:			/* VESA blanking */
885 		vga_vesa_blank(info, blank-1);
886 		info->vesa_blanked = 1;
887 		break;
888 	}
889 }
890 
vga16fb_init(void)891 int __init vga16fb_init(void)
892 {
893 	int i,j;
894 
895 	printk(KERN_DEBUG "vga16fb: initializing\n");
896 
897 	/* XXX share VGA_FB_PHYS region with vgacon */
898 
899         vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
900 	if (!vga16fb.video_vbase) {
901 		printk(KERN_ERR "vga16fb: unable to map device\n");
902 		return -ENOMEM;
903 	}
904 	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
905 
906 	vga16fb.isVGA = ORIG_VIDEO_ISVGA;
907 	vga16fb.palette_blanked = 0;
908 	vga16fb.vesa_blanked = 0;
909 
910 	i = vga16fb.isVGA? 6 : 2;
911 
912 	vga16fb_defined.red.length   = i;
913 	vga16fb_defined.green.length = i;
914 	vga16fb_defined.blue.length  = i;
915 	for(i = 0; i < 16; i++) {
916 		j = color_table[i];
917 		palette[i].red   = default_red[j];
918 		palette[i].green = default_grn[j];
919 		palette[i].blue  = default_blu[j];
920 	}
921 
922 	/* XXX share VGA I/O region with vgacon and others */
923 
924 	disp.var = vga16fb_defined;
925 
926 	/* name should not depend on EGA/VGA */
927 	strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
928 	vga16fb.fb_info.changevar = NULL;
929 	vga16fb.fb_info.node = -1;
930 	vga16fb.fb_info.fbops = &vga16fb_ops;
931 	vga16fb.fb_info.disp=&disp;
932 	vga16fb.fb_info.switch_con=&vga16fb_switch;
933 	vga16fb.fb_info.updatevar=&vga16fb_update_var;
934 	vga16fb.fb_info.blank=&vga16fb_blank;
935 	vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
936 	vga16fb_set_disp(-1, &vga16fb);
937 
938 	if (register_framebuffer(&vga16fb.fb_info)<0) {
939 		iounmap(vga16fb.video_vbase);
940 		return -EINVAL;
941 	}
942 
943 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
944 	       GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
945 
946 	return 0;
947 }
948 
vga16fb_exit(void)949 static void __exit vga16fb_exit(void)
950 {
951     unregister_framebuffer(&vga16fb.fb_info);
952     iounmap(vga16fb.video_vbase);
953     /* XXX unshare VGA regions */
954 }
955 
956 #ifdef MODULE
957 MODULE_LICENSE("GPL");
958 module_init(vga16fb_init);
959 #endif
960 module_exit(vga16fb_exit);
961 
962 
963 /*
964  * Overrides for Emacs so that we follow Linus's tabbing style.
965  * ---------------------------------------------------------------------------
966  * Local variables:
967  * c-basic-offset: 8
968  * End:
969  */
970 
971