Import 2.3.15pre1
[davej-history.git] / drivers / video / vga16fb.c
blob723bef47657faa94e84cf72a853e50c64b5c9ee1
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 /* --------------------------------------------------------------------- */
38 * card parameters
41 static struct vga16fb_info {
42 struct fb_info fb_info;
43 char *video_vbase; /* 0xa0000 map address */
44 int isVGA;
46 /* structure holding original VGA register settings when the
47 screen is blanked */
48 struct {
49 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
50 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
51 unsigned char CrtMiscIO; /* Miscellaneous register */
52 unsigned char HorizontalTotal; /* CRT-Controller:00h */
53 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
54 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
55 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
56 unsigned char Overflow; /* CRT-Controller:07h */
57 unsigned char StartVertRetrace; /* CRT-Controller:10h */
58 unsigned char EndVertRetrace; /* CRT-Controller:11h */
59 unsigned char ModeControl; /* CRT-Controller:17h */
60 unsigned char ClockingMode; /* Seq-Controller:01h */
61 } vga_state;
63 int palette_blanked;
64 int vesa_blanked;
65 } vga16fb;
68 struct vga16fb_par {
69 u8 crtc[VGA_CRT_C];
70 u8 atc[VGA_ATT_C];
71 u8 gdc[VGA_GFX_C];
72 u8 seq[VGA_SEQ_C];
73 u8 misc;
74 u8 vss;
75 struct fb_var_screeninfo var;
78 /* --------------------------------------------------------------------- */
80 static struct fb_var_screeninfo vga16fb_defined = {
81 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
82 0,0, /* virtual -> visible no offset */
83 4, /* depth -> load bits_per_pixel */
84 0, /* greyscale ? */
85 {0,0,0}, /* R */
86 {0,0,0}, /* G */
87 {0,0,0}, /* B */
88 {0,0,0}, /* transparency */
89 0, /* standard pixel format */
90 FB_ACTIVATE_NOW,
91 -1,-1,
93 39721, 48, 16, 39, 8,
94 96, 2, 0, /* No sync info */
95 FB_VMODE_NONINTERLACED,
96 {0,0,0,0,0,0}
99 static struct display disp;
100 static struct { u_short blue, green, red, pad; } palette[256];
102 static int currcon = 0;
104 /* --------------------------------------------------------------------- */
107 * Open/Release the frame buffer device
110 static int vga16fb_open(struct fb_info *info, int user)
113 * Nothing, only a usage count for the moment
115 MOD_INC_USE_COUNT;
116 return(0);
119 static int vga16fb_release(struct fb_info *info, int user)
121 MOD_DEC_USE_COUNT;
122 return(0);
125 static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var)
127 u32 pos = (var->xres_virtual * var->yoffset + var->xoffset) >> 3;
128 outb(VGA_CRTC_START_HI, VGA_CRT_IC);
129 outb(pos >> 8, VGA_CRT_DC);
130 outb(VGA_CRTC_START_LO, VGA_CRT_IC);
131 outb(pos & 0xFF, VGA_CRT_DC);
132 #if 0
133 /* if someone supports xoffset in bit resolution */
134 inb(VGA_IS1_RC); /* reset flip-flop */
135 outb(VGA_ATC_PEL, VGA_ATT_IW);
136 outb(xoffset & 7, VGA_ATT_IW);
137 inb(VGA_IS1_RC);
138 outb(0x20, VGA_ATT_IW);
139 #endif
142 static int vga16fb_update_var(int con, struct fb_info *info)
144 vga16fb_pan_var(info, &fb_display[con].var);
145 return 0;
148 static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con,
149 struct fb_info *info)
151 struct display *p;
153 if (con < 0)
154 p = &disp;
155 else
156 p = fb_display + con;
158 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
159 strcpy(fix->id,"VGA16 VGA");
161 fix->smem_start = 0xa0000;
162 fix->smem_len = 65536;
163 fix->type = FB_TYPE_VGA_PLANES;
164 fix->visual = FB_VISUAL_PSEUDOCOLOR;
165 fix->xpanstep = 8;
166 fix->ypanstep = 1;
167 fix->ywrapstep = 0;
168 fix->line_length = p->var.xres_virtual / 8;
169 return 0;
172 static int vga16fb_get_var(struct fb_var_screeninfo *var, int con,
173 struct fb_info *info)
175 if(con==-1)
176 memcpy(var, &vga16fb_defined, sizeof(struct fb_var_screeninfo));
177 else
178 *var=fb_display[con].var;
179 return 0;
182 static void vga16fb_set_disp(int con, struct vga16fb_info *info)
184 struct fb_fix_screeninfo fix;
185 struct display *display;
187 if (con < 0)
188 display = &disp;
189 else
190 display = fb_display + con;
193 vga16fb_get_fix(&fix, con, &info->fb_info);
195 display->screen_base = info->video_vbase;
196 display->visual = fix.visual;
197 display->type = fix.type;
198 display->type_aux = fix.type_aux;
199 display->ypanstep = fix.ypanstep;
200 display->ywrapstep = fix.ywrapstep;
201 display->line_length = fix.line_length;
202 display->next_line = fix.line_length;
203 display->can_soft_blank = 1;
204 display->inverse = 0;
206 if (info->isVGA)
207 display->dispsw = &fbcon_vga_planes;
208 else
209 display->dispsw = &fbcon_ega_planes;
210 display->scrollmode = SCROLL_YREDRAW;
213 static void vga16fb_encode_var(struct fb_var_screeninfo *var,
214 const struct vga16fb_par *par,
215 const struct vga16fb_info *info)
217 *var = par->var;
220 static void vga16fb_clock_chip(struct vga16fb_par *par,
221 unsigned int pixclock,
222 const struct vga16fb_info *info)
224 static struct {
225 u32 pixclock;
226 u8 misc;
227 u8 seq_clock_mode;
228 } *ptr, *best, vgaclocks[] = {
229 { 79442 /* 12.587 */, 0x00, 0x08},
230 { 70616 /* 14.161 */, 0x04, 0x08},
231 { 39721 /* 25.175 */, 0x00, 0x00},
232 { 35308 /* 28.322 */, 0x04, 0x00},
233 { 0 /* bad */, 0x00, 0x00}};
234 int err;
236 best = vgaclocks;
237 err = pixclock - best->pixclock;
238 if (err < 0) err = -err;
239 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
240 int tmp;
242 tmp = pixclock - ptr->pixclock;
243 if (tmp < 0) tmp = -tmp;
244 if (tmp < err) {
245 err = tmp;
246 best = ptr;
249 par->misc |= best->misc;
250 par->seq[VGA_SEQ_CLOCK_MODE] |= best->seq_clock_mode;
251 par->var.pixclock = best->pixclock;
254 #define FAIL(X) return -EINVAL
256 static int vga16fb_decode_var(const struct fb_var_screeninfo *var,
257 struct vga16fb_par *par,
258 const struct vga16fb_info *info)
260 u32 xres, right, hslen, left, xtotal;
261 u32 yres, lower, vslen, upper, ytotal;
262 u32 vxres, xoffset, vyres, yoffset;
263 u32 pos;
264 u8 r7, rMode;
265 int i;
267 if (var->bits_per_pixel != 4)
268 return -EINVAL;
269 xres = (var->xres + 7) & ~7;
270 vxres = (var->xres_virtual + 0xF) & ~0xF;
271 xoffset = (var->xoffset + 7) & ~7;
272 left = (var->left_margin + 7) & ~7;
273 right = (var->right_margin + 7) & ~7;
274 hslen = (var->hsync_len + 7) & ~7;
276 if (vxres < xres)
277 vxres = xres;
278 if (xres + xoffset > vxres)
279 xoffset = vxres - xres;
281 par->var.xres = xres;
282 par->var.right_margin = right;
283 par->var.hsync_len = hslen;
284 par->var.left_margin = left;
285 par->var.xres_virtual = vxres;
286 par->var.xoffset = xoffset;
288 xres >>= 3;
289 right >>= 3;
290 hslen >>= 3;
291 left >>= 3;
292 vxres >>= 3;
293 xtotal = xres + right + hslen + left;
294 if (xtotal >= 256)
295 FAIL("xtotal too big");
296 if (hslen > 32)
297 FAIL("hslen too big");
298 if (right + hslen + left > 64)
299 FAIL("hblank too big");
300 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
301 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
302 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
303 pos = xres + right;
304 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
305 pos += hslen;
306 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
307 pos += left - 2; /* blank_end + 2 <= total + 5 */
308 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
309 if (pos & 0x20)
310 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
312 yres = var->yres;
313 lower = var->lower_margin;
314 vslen = var->vsync_len;
315 upper = var->upper_margin;
316 vyres = var->yres_virtual;
317 yoffset = var->yoffset;
319 if (yres > vyres)
320 vyres = yres;
321 if (vxres * vyres > 65536) {
322 vyres = 65536 / vxres;
323 if (vyres < yres)
324 return -ENOMEM;
326 if (yoffset + yres > vyres)
327 yoffset = vyres - yres;
328 par->var.yres = yres;
329 par->var.lower_margin = lower;
330 par->var.vsync_len = vslen;
331 par->var.upper_margin = upper;
332 par->var.yres_virtual = vyres;
333 par->var.yoffset = yoffset;
335 if (var->vmode & FB_VMODE_DOUBLE) {
336 yres <<= 1;
337 lower <<= 1;
338 vslen <<= 1;
339 upper <<= 1;
341 ytotal = yres + lower + vslen + upper;
342 if (ytotal > 1024) {
343 ytotal >>= 1;
344 yres >>= 1;
345 lower >>= 1;
346 vslen >>= 1;
347 upper >>= 1;
348 rMode = 0x04;
349 } else
350 rMode = 0x00;
351 if (ytotal > 1024)
352 FAIL("ytotal too big");
353 if (vslen > 16)
354 FAIL("vslen too big");
355 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
356 r7 = 0x10; /* disable linecompare */
357 if (ytotal & 0x100) r7 |= 0x01;
358 if (ytotal & 0x200) r7 |= 0x20;
359 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
360 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
361 par->var.vmode = var->vmode;
362 if (var->vmode & FB_VMODE_DOUBLE)
363 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
364 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
365 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
366 pos = yoffset * vxres + (xoffset >> 3);
367 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
368 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
369 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
370 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
371 pos = yres - 1;
372 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
373 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
374 if (pos & 0x100)
375 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
376 if (pos & 0x200) {
377 r7 |= 0x40; /* 0x40 -> DISP_END */
378 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
380 pos += lower;
381 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
382 if (pos & 0x100)
383 r7 |= 0x04;
384 if (pos & 0x200)
385 r7 |= 0x80;
386 pos += vslen;
387 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) | 0x10; /* disabled IRQ */
388 pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
389 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
390 but some SVGA chips requires all 8 bits to set */
391 if (vxres >= 512)
392 FAIL("vxres too long");
393 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
394 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;
395 par->crtc[VGA_CRTC_MODE] = rMode | 0xE3;
396 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
397 par->crtc[VGA_CRTC_OVERFLOW] = r7;
399 par->vss = 0x00; /* 3DA */
401 for (i = 0x00; i < 0x10; i++)
402 par->atc[i] = i;
403 par->atc[VGA_ATC_MODE] = 0x81;
404 par->atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
405 par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
406 par->atc[VGA_ATC_PEL] = xoffset & 7;
407 par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
409 par->misc = 0xC3; /* enable CPU, ports 0x3Dx, positive sync */
410 par->var.sync = var->sync;
411 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
412 par->misc &= ~0x40;
413 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
414 par->misc &= ~0x80;
416 par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
417 par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
418 par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
419 par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
421 par->gdc[VGA_GFX_SR_VALUE] = 0x00;
422 par->gdc[VGA_GFX_SR_ENABLE] = 0x0F;
423 par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
424 par->gdc[VGA_GFX_DATA_ROTATE] = 0x20;
425 par->gdc[VGA_GFX_PLANE_READ] = 0;
426 par->gdc[VGA_GFX_MODE] = 0x00;
427 par->gdc[VGA_GFX_MISC] = 0x05;
428 par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
429 par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
431 vga16fb_clock_chip(par, var->pixclock, info);
433 par->var.bits_per_pixel = 4;
434 par->var.grayscale = var->grayscale;
435 par->var.red.offset = par->var.green.offset = par->var.blue.offset =
436 par->var.transp.offset = 0;
437 par->var.red.length = par->var.green.length = par->var.blue.length =
438 (info->isVGA) ? 6 : 2;
439 par->var.transp.length = 0;
440 par->var.nonstd = 0;
441 par->var.activate = FB_ACTIVATE_NOW;
442 par->var.height = -1;
443 par->var.width = -1;
444 par->var.accel_flags = 0;
446 return 0;
448 #undef FAIL
450 static int vga16fb_set_par(const struct vga16fb_par *par,
451 struct vga16fb_info *info)
453 int i;
455 outb(inb(VGA_MIS_R) | 0x01, VGA_MIS_W);
457 /* Enable graphics register modification */
458 if (!info->isVGA) {
459 outb(0x00, EGA_GFX_E0);
460 outb(0x01, EGA_GFX_E1);
463 /* update misc output register */
464 outb(par->misc, VGA_MIS_W);
466 /* synchronous reset on */
467 outb(0x00, VGA_SEQ_I);
468 outb(0x01, VGA_SEQ_D);
470 /* write sequencer registers */
471 outb(1, VGA_SEQ_I);
472 outb(par->seq[1] | 0x20, VGA_SEQ_D);
473 for (i = 2; i < VGA_SEQ_C; i++) {
474 outb(i, VGA_SEQ_I);
475 outb(par->seq[i], VGA_SEQ_D);
478 /* synchronous reset off */
479 outb(0x00, VGA_SEQ_I);
480 outb(0x03, VGA_SEQ_D);
482 /* deprotect CRT registers 0-7 */
483 outb(0x11, VGA_CRT_IC);
484 outb(par->crtc[0x11], VGA_CRT_DC);
486 /* write CRT registers */
487 for (i = 0; i < VGA_CRT_C; i++) {
488 outb(i, VGA_CRT_IC);
489 outb(par->crtc[i], VGA_CRT_DC);
492 /* write graphics controller registers */
493 for (i = 0; i < VGA_GFX_C; i++) {
494 outb(i, VGA_GFX_I);
495 outb(par->gdc[i], VGA_GFX_D);
498 /* write attribute controller registers */
499 for (i = 0; i < VGA_ATT_C; i++) {
500 inb_p(VGA_IS1_RC); /* reset flip-flop */
501 outb_p(i, VGA_ATT_IW);
502 outb_p(par->atc[i], VGA_ATT_IW);
505 /* Wait for screen to stabilize. */
506 mdelay(50);
508 outb(0x01, VGA_SEQ_I);
509 outb(par->seq[1], VGA_SEQ_D);
511 inb(VGA_IS1_RC);
512 outb(0x20, VGA_ATT_IW);
514 return 0;
517 static int vga16fb_set_var(struct fb_var_screeninfo *var, int con,
518 struct fb_info *fb)
520 struct vga16fb_info *info = (struct vga16fb_info*)fb;
521 struct vga16fb_par par;
522 struct display *display;
523 int err;
525 if (con < 0)
526 display = fb->disp;
527 else
528 display = fb_display + con;
529 if ((err = vga16fb_decode_var(var, &par, info)) != 0)
530 return err;
531 vga16fb_encode_var(var, &par, info);
533 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
534 return 0;
536 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
537 u32 oldxres, oldyres, oldvxres, oldvyres, oldbpp;
539 oldxres = display->var.xres;
540 oldyres = display->var.yres;
541 oldvxres = display->var.xres_virtual;
542 oldvyres = display->var.yres_virtual;
543 oldbpp = display->var.bits_per_pixel;
545 display->var = *var;
547 if (oldxres != var->xres || oldyres != var->yres ||
548 oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
549 oldbpp != var->bits_per_pixel) {
550 vga16fb_set_disp(con, info);
551 if (info->fb_info.changevar)
552 info->fb_info.changevar(con);
554 if (con == currcon)
555 vga16fb_set_par(&par, info);
558 return 0;
561 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
563 static unsigned char map[] = { 000, 001, 010, 011 };
564 int val;
566 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
567 inb_p(0x3DA); /* ! 0x3BA */
568 outb_p(regno, 0x3C0);
569 outb_p(val, 0x3C0);
570 inb_p(0x3DA); /* some clones need it */
571 outb_p(0x20, 0x3C0); /* unblank screen */
574 static int vga16_getcolreg(unsigned regno, unsigned *red, unsigned *green,
575 unsigned *blue, unsigned *transp,
576 struct fb_info *fb_info)
579 * Read a single color register and split it into colors/transparent.
580 * Return != 0 for invalid regno.
583 if (regno >= 16)
584 return 1;
586 *red = palette[regno].red;
587 *green = palette[regno].green;
588 *blue = palette[regno].blue;
589 *transp = 0;
590 return 0;
593 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
595 outb(regno, dac_reg);
596 outb(red >> 10, dac_val);
597 outb(green >> 10, dac_val);
598 outb(blue >> 10, dac_val);
601 static int vga16_setcolreg(unsigned regno, unsigned red, unsigned green,
602 unsigned blue, unsigned transp,
603 struct fb_info *fb_info)
605 int gray;
608 * Set a single color register. The values supplied are
609 * already rounded down to the hardware's capabilities
610 * (according to the entries in the `var' structure). Return
611 * != 0 for invalid regno.
614 if (regno >= 16)
615 return 1;
617 palette[regno].red = red;
618 palette[regno].green = green;
619 palette[regno].blue = blue;
621 if (currcon < 0)
622 gray = disp.var.grayscale;
623 else
624 gray = fb_display[currcon].var.grayscale;
625 if (gray) {
626 /* gray = 0.30*R + 0.59*G + 0.11*B */
627 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
629 if (((struct vga16fb_info *) fb_info)->isVGA)
630 vga16_setpalette(regno,red,green,blue);
631 else
632 ega16_setpalette(regno,red,green,blue);
634 return 0;
637 static void do_install_cmap(int con, struct fb_info *info)
639 if (con != currcon)
640 return;
641 if (fb_display[con].cmap.len)
642 fb_set_cmap(&fb_display[con].cmap, 1, vga16_setcolreg, info);
643 else
644 fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg,
645 info);
648 static int vga16fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
649 struct fb_info *info)
651 if (con == currcon) /* current console? */
652 return fb_get_cmap(cmap, kspc, vga16_getcolreg, info);
653 else if (fb_display[con].cmap.len) /* non default colormap? */
654 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
655 else
656 fb_copy_cmap(fb_default_cmap(16),
657 cmap, kspc ? 0 : 2);
658 return 0;
661 static int vga16fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
662 struct fb_info *info)
664 int err;
666 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
667 err = fb_alloc_cmap(&fb_display[con].cmap,16,0);
668 if (err)
669 return err;
671 if (con == currcon) /* current console? */
672 return fb_set_cmap(cmap, kspc, vga16_setcolreg, info);
673 else
674 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
675 return 0;
678 static int vga16fb_pan_display(struct fb_var_screeninfo *var, int con,
679 struct fb_info *info)
681 if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
682 var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
683 return -EINVAL;
684 if (con == currcon)
685 vga16fb_pan_var(info, var);
686 fb_display[con].var.xoffset = var->xoffset;
687 fb_display[con].var.yoffset = var->yoffset;
688 fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
689 return 0;
692 static int vga16fb_ioctl(struct inode *inode, struct file *file,
693 unsigned int cmd, unsigned long arg, int con,
694 struct fb_info *info)
696 return -EINVAL;
699 static struct fb_ops vga16fb_ops = {
700 vga16fb_open,
701 vga16fb_release,
702 vga16fb_get_fix,
703 vga16fb_get_var,
704 vga16fb_set_var,
705 vga16fb_get_cmap,
706 vga16fb_set_cmap,
707 vga16fb_pan_display,
708 vga16fb_ioctl
711 int vga16fb_setup(char *options)
713 char *this_opt;
715 vga16fb.fb_info.fontname[0] = '\0';
717 if (!options || !*options)
718 return 0;
720 for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
721 if (!*this_opt) continue;
723 if (!strncmp(this_opt, "font:", 5))
724 strcpy(vga16fb.fb_info.fontname, this_opt+5);
726 return 0;
729 static int vga16fb_switch(int con, struct fb_info *fb)
731 struct vga16fb_par par;
732 struct vga16fb_info *info = (struct vga16fb_info*)fb;
734 /* Do we have to save the colormap? */
735 if (fb_display[currcon].cmap.len)
736 fb_get_cmap(&fb_display[currcon].cmap, 1, vga16_getcolreg,
737 fb);
739 currcon = con;
740 vga16fb_decode_var(&fb_display[con].var, &par, info);
741 vga16fb_set_par(&par, info);
742 vga16fb_set_disp(con, info);
744 /* Install new colormap */
745 do_install_cmap(con, fb);
746 /* vga16fb_update_var(con, fb); */
747 return 1;
750 /* The following VESA blanking code is taken from vgacon.c. The VGA
751 blanking code was originally by Huang shi chao, and modified by
752 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
753 (tjd@barefoot.org) for Linux. */
754 #define attrib_port 0x3c0
755 #define seq_port_reg 0x3c4
756 #define seq_port_val 0x3c5
757 #define gr_port_reg 0x3ce
758 #define gr_port_val 0x3cf
759 #define video_misc_rd 0x3cc
760 #define video_misc_wr 0x3c2
761 #define vga_video_port_reg 0x3d4
762 #define vga_video_port_val 0x3d5
764 static void vga_vesa_blank(struct vga16fb_info *info, int mode)
766 unsigned char SeqCtrlIndex;
767 unsigned char CrtCtrlIndex;
769 cli();
770 SeqCtrlIndex = inb_p(seq_port_reg);
771 CrtCtrlIndex = inb_p(vga_video_port_reg);
773 /* save original values of VGA controller registers */
774 if(!info->vesa_blanked) {
775 info->vga_state.CrtMiscIO = inb_p(video_misc_rd);
776 sti();
778 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
779 info->vga_state.HorizontalTotal = inb_p(vga_video_port_val);
780 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
781 info->vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
782 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
783 info->vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
784 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
785 info->vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
786 outb_p(0x07,vga_video_port_reg); /* Overflow */
787 info->vga_state.Overflow = inb_p(vga_video_port_val);
788 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
789 info->vga_state.StartVertRetrace = inb_p(vga_video_port_val);
790 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
791 info->vga_state.EndVertRetrace = inb_p(vga_video_port_val);
792 outb_p(0x17,vga_video_port_reg); /* ModeControl */
793 info->vga_state.ModeControl = inb_p(vga_video_port_val);
794 outb_p(0x01,seq_port_reg); /* ClockingMode */
795 info->vga_state.ClockingMode = inb_p(seq_port_val);
798 /* assure that video is enabled */
799 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
800 cli();
801 outb_p(0x01,seq_port_reg);
802 outb_p(info->vga_state.ClockingMode | 0x20,seq_port_val);
804 /* test for vertical retrace in process.... */
805 if ((info->vga_state.CrtMiscIO & 0x80) == 0x80)
806 outb_p(info->vga_state.CrtMiscIO & 0xef,video_misc_wr);
809 * Set <End of vertical retrace> to minimum (0) and
810 * <Start of vertical Retrace> to maximum (incl. overflow)
811 * Result: turn off vertical sync (VSync) pulse.
813 if (mode & VESA_VSYNC_SUSPEND) {
814 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
815 outb_p(0xff,vga_video_port_val); /* maximum value */
816 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
817 outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
818 outb_p(0x07,vga_video_port_reg); /* Overflow */
819 outb_p(info->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
822 if (mode & VESA_HSYNC_SUSPEND) {
824 * Set <End of horizontal retrace> to minimum (0) and
825 * <Start of horizontal Retrace> to maximum
826 * Result: turn off horizontal sync (HSync) pulse.
828 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
829 outb_p(0xff,vga_video_port_val); /* maximum */
830 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
831 outb_p(0x00,vga_video_port_val); /* minimum (0) */
834 /* restore both index registers */
835 outb_p(SeqCtrlIndex,seq_port_reg);
836 outb_p(CrtCtrlIndex,vga_video_port_reg);
837 sti();
840 static void vga_vesa_unblank(struct vga16fb_info *info)
842 unsigned char SeqCtrlIndex;
843 unsigned char CrtCtrlIndex;
845 cli();
846 SeqCtrlIndex = inb_p(seq_port_reg);
847 CrtCtrlIndex = inb_p(vga_video_port_reg);
849 /* restore original values of VGA controller registers */
850 outb_p(info->vga_state.CrtMiscIO,video_misc_wr);
852 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
853 outb_p(info->vga_state.HorizontalTotal,vga_video_port_val);
854 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
855 outb_p(info->vga_state.HorizDisplayEnd,vga_video_port_val);
856 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
857 outb_p(info->vga_state.StartHorizRetrace,vga_video_port_val);
858 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
859 outb_p(info->vga_state.EndHorizRetrace,vga_video_port_val);
860 outb_p(0x07,vga_video_port_reg); /* Overflow */
861 outb_p(info->vga_state.Overflow,vga_video_port_val);
862 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
863 outb_p(info->vga_state.StartVertRetrace,vga_video_port_val);
864 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
865 outb_p(info->vga_state.EndVertRetrace,vga_video_port_val);
866 outb_p(0x17,vga_video_port_reg); /* ModeControl */
867 outb_p(info->vga_state.ModeControl,vga_video_port_val);
868 outb_p(0x01,seq_port_reg); /* ClockingMode */
869 outb_p(info->vga_state.ClockingMode,seq_port_val);
871 /* restore index/control registers */
872 outb_p(SeqCtrlIndex,seq_port_reg);
873 outb_p(CrtCtrlIndex,vga_video_port_reg);
874 sti();
877 static void vga_pal_blank(void)
879 int i;
881 for (i=0; i<16; i++) {
882 outb_p (i, dac_reg) ;
883 outb_p (0, dac_val) ;
884 outb_p (0, dac_val) ;
885 outb_p (0, dac_val) ;
889 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
890 static void vga16fb_blank(int blank, struct fb_info *fb_info)
892 struct vga16fb_info *info = (struct vga16fb_info*)fb_info;
894 switch (blank) {
895 case 0: /* Unblank */
896 if (info->vesa_blanked) {
897 vga_vesa_unblank(info);
898 info->vesa_blanked = 0;
900 if (info->palette_blanked) {
901 do_install_cmap(currcon, fb_info);
902 info->palette_blanked = 0;
904 break;
905 case 1: /* blank */
906 vga_pal_blank();
907 info->palette_blanked = 1;
908 break;
909 default: /* VESA blanking */
910 vga_vesa_blank(info, blank-1);
911 info->vesa_blanked = 1;
912 break;
916 int __init vga16_init(void)
918 int i,j;
920 printk(KERN_DEBUG "vga16fb: initializing\n");
922 vga16fb.video_vbase = ioremap((unsigned long)0xa0000, 65536);
923 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
925 vga16fb.isVGA = ORIG_VIDEO_ISVGA;
926 vga16fb.palette_blanked = 0;
927 vga16fb.vesa_blanked = 0;
929 i = vga16fb.isVGA? 6 : 2;
931 vga16fb_defined.red.length = i;
932 vga16fb_defined.green.length = i;
933 vga16fb_defined.blue.length = i;
934 for(i = 0; i < 16; i++) {
935 j = color_table[i];
936 palette[i].red = default_red[j];
937 palette[i].green = default_grn[j];
938 palette[i].blue = default_blu[j];
940 if (vga16fb.isVGA)
941 request_region(0x3c0, 32, "vga+");
942 else
943 request_region(0x3C0, 32, "ega");
945 disp.var = vga16fb_defined;
947 /* name should not depend on EGA/VGA */
948 strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
949 vga16fb.fb_info.changevar = NULL;
950 vga16fb.fb_info.node = -1;
951 vga16fb.fb_info.fbops = &vga16fb_ops;
952 vga16fb.fb_info.disp=&disp;
953 vga16fb.fb_info.switch_con=&vga16fb_switch;
954 vga16fb.fb_info.updatevar=&vga16fb_update_var;
955 vga16fb.fb_info.blank=&vga16fb_blank;
956 vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
957 vga16fb_set_disp(-1, &vga16fb);
959 if (register_framebuffer(&vga16fb.fb_info)<0)
960 return -EINVAL;
962 printk(KERN_INFO "fb%d: %s frame buffer device\n",
963 GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
965 return 0;
968 #ifndef MODULE
969 int __init vga16fb_init(void)
971 return vga16_init();
974 #else /* MODULE */
976 int init_module(void)
978 return vga16_init();
981 void cleanup_module(void)
983 unregister_framebuffer(&vga16fb.fb_info);
984 release_region(0x3c0, 32);
985 iounmap(vga16fb.video_vbase);
988 #endif
991 * Overrides for Emacs so that we follow Linus's tabbing style.
992 * ---------------------------------------------------------------------------
993 * Local variables:
994 * c-basic-offset: 8
995 * End: