2 * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
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>
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. */
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
17 #include <linux/tty.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
21 #include <linux/console.h>
22 #include <linux/selection.h>
23 #include <linux/ioport.h>
24 #include <linux/init.h>
28 #include <video/fbcon.h>
29 #include <video/fbcon-vga-planes.h>
32 #define dac_reg (0x3c8)
33 #define dac_val (0x3c9)
35 #define VGA_FB_PHYS 0xA0000
36 #define VGA_FB_PHYS_LEN 65536
38 /* --------------------------------------------------------------------- */
44 static struct vga16fb_info {
45 struct fb_info fb_info;
46 char *video_vbase; /* 0xa0000 map address */
49 /* structure holding original VGA register settings when the
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 */
78 struct fb_var_screeninfo var;
81 /* --------------------------------------------------------------------- */
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 */
91 {0,0,0}, /* transparency */
92 0, /* standard pixel format */
97 96, 2, 0, /* No sync info */
98 FB_VMODE_NONINTERLACED,
102 static struct display disp;
103 static struct { u_short blue, green, red, pad; } palette[256];
105 static int currcon = 0;
107 /* --------------------------------------------------------------------- */
109 static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var)
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);
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);
122 outb(0x20, VGA_ATT_IW);
126 static int vga16fb_update_var(int con, struct fb_info *info)
128 vga16fb_pan_var(info, &fb_display[con].var);
132 static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con,
133 struct fb_info *info)
140 p = fb_display + con;
142 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
143 strcpy(fix->id,"VGA16 VGA");
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;
152 fix->line_length = p->var.xres_virtual / 8;
156 static int vga16fb_get_var(struct fb_var_screeninfo *var, int con,
157 struct fb_info *info)
160 memcpy(var, &vga16fb_defined, sizeof(struct fb_var_screeninfo));
162 *var=fb_display[con].var;
166 static void vga16fb_set_disp(int con, struct vga16fb_info *info)
168 struct fb_fix_screeninfo fix;
169 struct display *display;
174 display = fb_display + con;
177 vga16fb_get_fix(&fix, con, &info->fb_info);
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;
191 display->dispsw = &fbcon_vga_planes;
193 display->dispsw = &fbcon_ega_planes;
194 display->scrollmode = SCROLL_YREDRAW;
197 static void vga16fb_encode_var(struct fb_var_screeninfo *var,
198 const struct vga16fb_par *par,
199 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)
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}};
221 err = pixclock - best->pixclock;
222 if (err < 0) err = -err;
223 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
226 tmp = pixclock - ptr->pixclock;
227 if (tmp < 0) tmp = -tmp;
233 par->misc |= best->misc;
234 par->seq[VGA_SEQ_CLOCK_MODE] |= best->seq_clock_mode;
235 par->var.pixclock = best->pixclock;
238 #define FAIL(X) return -EINVAL
240 static int vga16fb_decode_var(const struct fb_var_screeninfo *var,
241 struct vga16fb_par *par,
242 const struct vga16fb_info *info)
244 u32 xres, right, hslen, left, xtotal;
245 u32 yres, lower, vslen, upper, ytotal;
246 u32 vxres, xoffset, vyres, yoffset;
251 if (var->bits_per_pixel != 4)
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;
262 if (xres + xoffset > vxres)
263 xoffset = vxres - xres;
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;
277 xtotal = xres + right + hslen + left;
279 FAIL("xtotal too big");
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;
288 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
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;
294 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
297 lower = var->lower_margin;
298 vslen = var->vsync_len;
299 upper = var->upper_margin;
300 vyres = var->yres_virtual;
301 yoffset = var->yoffset;
305 if (vxres * vyres > 65536) {
306 vyres = 65536 / vxres;
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;
319 if (var->vmode & FB_VMODE_DOUBLE) {
325 ytotal = yres + lower + vslen + upper;
336 FAIL("ytotal too big");
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;
356 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
357 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
359 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
361 r7 |= 0x40; /* 0x40 -> DISP_END */
362 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
365 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
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 */
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;
383 par->vss = 0x00; /* 3DA */
385 for (i = 0x00; i < 0x10; 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;
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)
397 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
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;
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;
415 vga16fb_clock_chip(par, var->pixclock, info);
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;
425 par->var.activate = FB_ACTIVATE_NOW;
426 par->var.height = -1;
428 par->var.accel_flags = 0;
434 static int vga16fb_set_par(const struct vga16fb_par *par,
435 struct vga16fb_info *info)
439 outb(inb(VGA_MIS_R) | 0x01, VGA_MIS_W);
441 /* Enable graphics register modification */
443 outb(0x00, EGA_GFX_E0);
444 outb(0x01, EGA_GFX_E1);
447 /* update misc output register */
448 outb(par->misc, VGA_MIS_W);
450 /* synchronous reset on */
451 outb(0x00, VGA_SEQ_I);
452 outb(0x01, VGA_SEQ_D);
454 /* write sequencer registers */
456 outb(par->seq[1] | 0x20, VGA_SEQ_D);
457 for (i = 2; i < VGA_SEQ_C; i++) {
459 outb(par->seq[i], VGA_SEQ_D);
462 /* synchronous reset off */
463 outb(0x00, VGA_SEQ_I);
464 outb(0x03, VGA_SEQ_D);
466 /* deprotect CRT registers 0-7 */
467 outb(0x11, VGA_CRT_IC);
468 outb(par->crtc[0x11], VGA_CRT_DC);
470 /* write CRT registers */
471 for (i = 0; i < VGA_CRT_C; i++) {
473 outb(par->crtc[i], VGA_CRT_DC);
476 /* write graphics controller registers */
477 for (i = 0; i < VGA_GFX_C; i++) {
479 outb(par->gdc[i], VGA_GFX_D);
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);
489 /* Wait for screen to stabilize. */
492 outb(0x01, VGA_SEQ_I);
493 outb(par->seq[1], VGA_SEQ_D);
496 outb(0x20, VGA_ATT_IW);
501 static int vga16fb_set_var(struct fb_var_screeninfo *var, int con,
504 struct vga16fb_info *info = (struct vga16fb_info*)fb;
505 struct vga16fb_par par;
506 struct display *display;
512 display = fb_display + con;
513 if ((err = vga16fb_decode_var(var, &par, info)) != 0)
515 vga16fb_encode_var(var, &par, info);
517 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
520 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
521 u32 oldxres, oldyres, oldvxres, oldvyres, oldbpp;
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;
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);
539 vga16fb_set_par(&par, info);
545 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
547 static unsigned char map[] = { 000, 001, 010, 011 };
550 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
551 inb_p(0x3DA); /* ! 0x3BA */
552 outb_p(regno, 0x3C0);
554 inb_p(0x3DA); /* some clones need it */
555 outb_p(0x20, 0x3C0); /* unblank screen */
558 static int vga16_getcolreg(unsigned regno, unsigned *red, unsigned *green,
559 unsigned *blue, unsigned *transp,
560 struct fb_info *fb_info)
563 * Read a single color register and split it into colors/transparent.
564 * Return != 0 for invalid regno.
570 *red = palette[regno].red;
571 *green = palette[regno].green;
572 *blue = palette[regno].blue;
577 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
579 outb(regno, dac_reg);
580 outb(red >> 10, dac_val);
581 outb(green >> 10, dac_val);
582 outb(blue >> 10, dac_val);
585 static int vga16_setcolreg(unsigned regno, unsigned red, unsigned green,
586 unsigned blue, unsigned transp,
587 struct fb_info *fb_info)
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.
601 palette[regno].red = red;
602 palette[regno].green = green;
603 palette[regno].blue = blue;
606 gray = disp.var.grayscale;
608 gray = fb_display[currcon].var.grayscale;
610 /* gray = 0.30*R + 0.59*G + 0.11*B */
611 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
613 if (((struct vga16fb_info *) fb_info)->isVGA)
614 vga16_setpalette(regno,red,green,blue);
616 ega16_setpalette(regno,red,green,blue);
621 static void do_install_cmap(int con, struct fb_info *info)
625 if (fb_display[con].cmap.len)
626 fb_set_cmap(&fb_display[con].cmap, 1, vga16_setcolreg, info);
628 fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg,
632 static int vga16fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
633 struct fb_info *info)
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);
640 fb_copy_cmap(fb_default_cmap(16),
645 static int vga16fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
646 struct fb_info *info)
650 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
651 err = fb_alloc_cmap(&fb_display[con].cmap,16,0);
655 if (con == currcon) /* current console? */
656 return fb_set_cmap(cmap, kspc, vga16_setcolreg, info);
658 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
662 static int vga16fb_pan_display(struct fb_var_screeninfo *var, int con,
663 struct fb_info *info)
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)
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;
676 static struct fb_ops vga16fb_ops = {
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,
686 int vga16fb_setup(char *options)
690 vga16fb.fb_info.fontname[0] = '\0';
692 if (!options || !*options)
695 while ((this_opt = strsep(&options, ",")) != NULL) {
696 if (!*this_opt) continue;
698 if (!strncmp(this_opt, "font:", 5))
699 strcpy(vga16fb.fb_info.fontname, this_opt+5);
704 static int vga16fb_switch(int con, struct fb_info *fb)
706 struct vga16fb_par par;
707 struct vga16fb_info *info = (struct vga16fb_info*)fb;
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,
715 vga16fb_decode_var(&fb_display[con].var, &par, info);
716 vga16fb_set_par(&par, info);
717 vga16fb_set_disp(con, info);
719 /* Install new colormap */
720 do_install_cmap(con, fb);
721 /* vga16fb_update_var(con, fb); */
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
739 static void vga_vesa_blank(struct vga16fb_info *info, int mode)
741 unsigned char SeqCtrlIndex;
742 unsigned char CrtCtrlIndex;
745 SeqCtrlIndex = inb_p(seq_port_reg);
746 CrtCtrlIndex = inb_p(vga_video_port_reg);
748 /* save original values of VGA controller registers */
749 if(!info->vesa_blanked) {
750 info->vga_state.CrtMiscIO = inb_p(video_misc_rd);
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);
773 /* assure that video is enabled */
774 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
776 outb_p(0x01,seq_port_reg);
777 outb_p(info->vga_state.ClockingMode | 0x20,seq_port_val);
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);
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.
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 */
797 if (mode & VESA_HSYNC_SUSPEND) {
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.
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) */
809 /* restore both index registers */
810 outb_p(SeqCtrlIndex,seq_port_reg);
811 outb_p(CrtCtrlIndex,vga_video_port_reg);
815 static void vga_vesa_unblank(struct vga16fb_info *info)
817 unsigned char SeqCtrlIndex;
818 unsigned char CrtCtrlIndex;
821 SeqCtrlIndex = inb_p(seq_port_reg);
822 CrtCtrlIndex = inb_p(vga_video_port_reg);
824 /* restore original values of VGA controller registers */
825 outb_p(info->vga_state.CrtMiscIO,video_misc_wr);
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);
846 /* restore index/control registers */
847 outb_p(SeqCtrlIndex,seq_port_reg);
848 outb_p(CrtCtrlIndex,vga_video_port_reg);
852 static void vga_pal_blank(void)
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) ;
864 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
865 static void vga16fb_blank(int blank, struct fb_info *fb_info)
867 struct vga16fb_info *info = (struct vga16fb_info*)fb_info;
870 case 0: /* Unblank */
871 if (info->vesa_blanked) {
872 vga_vesa_unblank(info);
873 info->vesa_blanked = 0;
875 if (info->palette_blanked) {
876 do_install_cmap(currcon, fb_info);
877 info->palette_blanked = 0;
882 info->palette_blanked = 1;
884 default: /* VESA blanking */
885 vga_vesa_blank(info, blank-1);
886 info->vesa_blanked = 1;
891 int __init vga16fb_init(void)
895 printk(KERN_DEBUG "vga16fb: initializing\n");
897 /* XXX share VGA_FB_PHYS region with vgacon */
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");
904 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
906 vga16fb.isVGA = ORIG_VIDEO_ISVGA;
907 vga16fb.palette_blanked = 0;
908 vga16fb.vesa_blanked = 0;
910 i = vga16fb.isVGA? 6 : 2;
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++) {
917 palette[i].red = default_red[j];
918 palette[i].green = default_grn[j];
919 palette[i].blue = default_blu[j];
922 /* XXX share VGA I/O region with vgacon and others */
924 disp.var = vga16fb_defined;
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);
938 if (register_framebuffer(&vga16fb.fb_info)<0) {
939 iounmap(vga16fb.video_vbase);
943 printk(KERN_INFO "fb%d: %s frame buffer device\n",
944 GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
949 static void __exit vga16fb_exit(void)
951 unregister_framebuffer(&vga16fb.fb_info);
952 iounmap(vga16fb.video_vbase);
953 /* XXX unshare VGA regions */
957 MODULE_LICENSE("GPL");
958 module_init(vga16fb_init);
960 module_exit(vga16fb_exit);
964 * Overrides for Emacs so that we follow Linus's tabbing style.
965 * ---------------------------------------------------------------------------