Import 2.4.0-test5pre6
[davej-history.git] / drivers / video / vga16fb.c
blob35197da609f8dd58f621d624cba371359c4610ca
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>
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>
16 #include <linux/mm.h>
17 #include <linux/tty.h>
18 #include <linux/malloc.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>
26 #include <asm/io.h>
28 #include <video/fbcon.h>
29 #include <video/fbcon-vga-planes.h>
30 #include "vga.h"
32 #define dac_reg (0x3c8)
33 #define dac_val (0x3c9)
35 #define VGA_FB_PHYS 0xA0000
36 #define VGA_FB_PHYS_LEN 65535
38 /* --------------------------------------------------------------------- */
41 * card parameters
44 static struct vga16fb_info {
45 struct fb_info fb_info;
46 char *video_vbase; /* 0xa0000 map address */
47 int isVGA;
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;
66 int palette_blanked;
67 int vesa_blanked;
68 } vga16fb;
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;
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 */
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,
96 39721, 48, 16, 39, 8,
97 96, 2, 0, /* No sync info */
98 FB_VMODE_NONINTERLACED,
99 {0,0,0,0,0,0}
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);
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
126 static int vga16fb_update_var(int con, struct fb_info *info)
128 vga16fb_pan_var(info, &fb_display[con].var);
129 return 0;
132 static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con,
133 struct fb_info *info)
135 struct display *p;
137 if (con < 0)
138 p = &disp;
139 else
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;
149 fix->xpanstep = 8;
150 fix->ypanstep = 1;
151 fix->ywrapstep = 0;
152 fix->line_length = p->var.xres_virtual / 8;
153 return 0;
156 static int vga16fb_get_var(struct fb_var_screeninfo *var, int con,
157 struct fb_info *info)
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;
166 static void vga16fb_set_disp(int con, struct vga16fb_info *info)
168 struct fb_fix_screeninfo fix;
169 struct display *display;
171 if (con < 0)
172 display = &disp;
173 else
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;
190 if (info->isVGA)
191 display->dispsw = &fbcon_vga_planes;
192 else
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)
201 *var = par->var;
204 static void vga16fb_clock_chip(struct vga16fb_par *par,
205 unsigned int pixclock,
206 const struct vga16fb_info *info)
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;
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;
226 tmp = pixclock - ptr->pixclock;
227 if (tmp < 0) tmp = -tmp;
228 if (tmp < err) {
229 err = tmp;
230 best = ptr;
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;
247 u32 pos;
248 u8 r7, rMode;
249 int i;
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;
260 if (vxres < xres)
261 vxres = xres;
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;
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;
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;
303 if (yres > vyres)
304 vyres = yres;
305 if (vxres * vyres > 65536) {
306 vyres = 65536 / vxres;
307 if (vyres < yres)
308 return -ENOMEM;
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) {
320 yres <<= 1;
321 lower <<= 1;
322 vslen <<= 1;
323 upper <<= 1;
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 */
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;
383 par->vss = 0x00; /* 3DA */
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;
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;
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;
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;
430 return 0;
432 #undef FAIL
434 static int vga16fb_set_par(const struct vga16fb_par *par,
435 struct vga16fb_info *info)
437 int i;
439 outb(inb(VGA_MIS_R) | 0x01, VGA_MIS_W);
441 /* Enable graphics register modification */
442 if (!info->isVGA) {
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 */
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);
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++) {
472 outb(i, VGA_CRT_IC);
473 outb(par->crtc[i], VGA_CRT_DC);
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);
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. */
490 mdelay(50);
492 outb(0x01, VGA_SEQ_I);
493 outb(par->seq[1], VGA_SEQ_D);
495 inb(VGA_IS1_RC);
496 outb(0x20, VGA_ATT_IW);
498 return 0;
501 static int vga16fb_set_var(struct fb_var_screeninfo *var, int con,
502 struct fb_info *fb)
504 struct vga16fb_info *info = (struct vga16fb_info*)fb;
505 struct vga16fb_par par;
506 struct display *display;
507 int err;
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);
517 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
518 return 0;
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;
529 display->var = *var;
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);
538 if (con == currcon)
539 vga16fb_set_par(&par, info);
542 return 0;
545 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
547 static unsigned char map[] = { 000, 001, 010, 011 };
548 int val;
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 */
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.
567 if (regno >= 16)
568 return 1;
570 *red = palette[regno].red;
571 *green = palette[regno].green;
572 *blue = palette[regno].blue;
573 *transp = 0;
574 return 0;
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)
589 int gray;
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.
598 if (regno >= 16)
599 return 1;
601 palette[regno].red = red;
602 palette[regno].green = green;
603 palette[regno].blue = blue;
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;
613 if (((struct vga16fb_info *) fb_info)->isVGA)
614 vga16_setpalette(regno,red,green,blue);
615 else
616 ega16_setpalette(regno,red,green,blue);
618 return 0;
621 static void do_install_cmap(int con, struct fb_info *info)
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);
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);
639 else
640 fb_copy_cmap(fb_default_cmap(16),
641 cmap, kspc ? 0 : 2);
642 return 0;
645 static int vga16fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
646 struct fb_info *info)
648 int err;
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;
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;
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)
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;
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,
686 int vga16fb_setup(char *options)
688 char *this_opt;
690 vga16fb.fb_info.fontname[0] = '\0';
692 if (!options || !*options)
693 return 0;
695 for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
696 if (!*this_opt) continue;
698 if (!strncmp(this_opt, "font:", 5))
699 strcpy(vga16fb.fb_info.fontname, this_opt+5);
701 return 0;
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,
712 fb);
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);
719 /* Install new colormap */
720 do_install_cmap(con, fb);
721 /* vga16fb_update_var(con, fb); */
722 return 1;
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;
744 cli();
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);
751 sti();
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 */
775 cli();
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);
812 sti();
815 static void vga_vesa_unblank(struct vga16fb_info *info)
817 unsigned char SeqCtrlIndex;
818 unsigned char CrtCtrlIndex;
820 cli();
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);
849 sti();
852 static void vga_pal_blank(void)
854 int i;
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;
869 switch (blank) {
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;
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;
891 int __init vga16fb_init(void)
893 int i,j;
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 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
902 vga16fb.isVGA = ORIG_VIDEO_ISVGA;
903 vga16fb.palette_blanked = 0;
904 vga16fb.vesa_blanked = 0;
906 i = vga16fb.isVGA? 6 : 2;
908 vga16fb_defined.red.length = i;
909 vga16fb_defined.green.length = i;
910 vga16fb_defined.blue.length = i;
911 for(i = 0; i < 16; i++) {
912 j = color_table[i];
913 palette[i].red = default_red[j];
914 palette[i].green = default_grn[j];
915 palette[i].blue = default_blu[j];
918 /* XXX share VGA I/O region with vgacon and others */
920 disp.var = vga16fb_defined;
922 /* name should not depend on EGA/VGA */
923 strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
924 vga16fb.fb_info.changevar = NULL;
925 vga16fb.fb_info.node = -1;
926 vga16fb.fb_info.fbops = &vga16fb_ops;
927 vga16fb.fb_info.disp=&disp;
928 vga16fb.fb_info.switch_con=&vga16fb_switch;
929 vga16fb.fb_info.updatevar=&vga16fb_update_var;
930 vga16fb.fb_info.blank=&vga16fb_blank;
931 vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
932 vga16fb_set_disp(-1, &vga16fb);
934 if (register_framebuffer(&vga16fb.fb_info)<0)
935 return -EINVAL;
937 printk(KERN_INFO "fb%d: %s frame buffer device\n",
938 GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
940 return 0;
943 static void __exit vga16fb_exit(void)
945 unregister_framebuffer(&vga16fb.fb_info);
946 iounmap(vga16fb.video_vbase);
947 /* XXX unshare VGA regions */
950 #ifdef MODULE
951 module_init(vga16fb_init);
952 #endif
953 module_exit(vga16fb_exit);
957 * Overrides for Emacs so that we follow Linus's tabbing style.
958 * ---------------------------------------------------------------------------
959 * Local variables:
960 * c-basic-offset: 8
961 * End: