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/malloc.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 /* --------------------------------------------------------------------- */
41 static struct vga16fb_info
{
42 struct fb_info fb_info
;
43 char *video_vbase
; /* 0xa0000 map address */
46 /* structure holding original VGA register settings when the
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 */
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 */
88 {0,0,0}, /* transparency */
89 0, /* standard pixel format */
94 96, 2, 0, /* No sync info */
95 FB_VMODE_NONINTERLACED
,
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
119 static int vga16fb_release(struct fb_info
*info
, int user
)
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
);
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
);
138 outb(0x20, VGA_ATT_IW
);
142 static int vga16fb_update_var(int con
, struct fb_info
*info
)
144 vga16fb_pan_var(info
, &fb_display
[con
].var
);
148 static int vga16fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
149 struct fb_info
*info
)
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
;
168 fix
->line_length
= p
->var
.xres_virtual
/ 8;
172 static int vga16fb_get_var(struct fb_var_screeninfo
*var
, int con
,
173 struct fb_info
*info
)
176 memcpy(var
, &vga16fb_defined
, sizeof(struct fb_var_screeninfo
));
178 *var
=fb_display
[con
].var
;
182 static void vga16fb_set_disp(int con
, struct vga16fb_info
*info
)
184 struct fb_fix_screeninfo fix
;
185 struct display
*display
;
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;
207 display
->dispsw
= &fbcon_vga_planes
;
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
)
220 static void vga16fb_clock_chip(struct vga16fb_par
*par
,
221 unsigned int pixclock
,
222 const struct vga16fb_info
*info
)
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}};
237 err
= pixclock
- best
->pixclock
;
238 if (err
< 0) err
= -err
;
239 for (ptr
= vgaclocks
+ 1; ptr
->pixclock
; ptr
++) {
242 tmp
= pixclock
- ptr
->pixclock
;
243 if (tmp
< 0) tmp
= -tmp
;
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
;
267 if (var
->bits_per_pixel
!= 4)
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;
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
;
293 xtotal
= xres
+ right
+ hslen
+ left
;
295 FAIL("xtotal too big");
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;
304 par
->crtc
[VGA_CRTC_H_SYNC_START
] = pos
;
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;
310 par
->crtc
[VGA_CRTC_H_SYNC_END
] |= 0x80;
313 lower
= var
->lower_margin
;
314 vslen
= var
->vsync_len
;
315 upper
= var
->upper_margin
;
316 vyres
= var
->yres_virtual
;
317 yoffset
= var
->yoffset
;
321 if (vxres
* vyres
> 65536) {
322 vyres
= 65536 / vxres
;
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
) {
341 ytotal
= yres
+ lower
+ vslen
+ upper
;
352 FAIL("ytotal too big");
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;
372 par
->crtc
[VGA_CRTC_V_DISP_END
] = pos
& 0xFF;
373 par
->crtc
[VGA_CRTC_V_BLANK_START
] = pos
& 0xFF;
375 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
377 r7
|= 0x40; /* 0x40 -> DISP_END */
378 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
381 par
->crtc
[VGA_CRTC_V_SYNC_START
] = pos
& 0xFF;
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 */
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
++)
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
)
413 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
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;
441 par
->var
.activate
= FB_ACTIVATE_NOW
;
442 par
->var
.height
= -1;
444 par
->var
.accel_flags
= 0;
450 static int vga16fb_set_par(const struct vga16fb_par
*par
,
451 struct vga16fb_info
*info
)
455 outb(inb(VGA_MIS_R
) | 0x01, VGA_MIS_W
);
457 /* Enable graphics register modification */
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 */
472 outb(par
->seq
[1] | 0x20, VGA_SEQ_D
);
473 for (i
= 2; i
< VGA_SEQ_C
; 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
++) {
489 outb(par
->crtc
[i
], VGA_CRT_DC
);
492 /* write graphics controller registers */
493 for (i
= 0; i
< VGA_GFX_C
; 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. */
508 outb(0x01, VGA_SEQ_I
);
509 outb(par
->seq
[1], VGA_SEQ_D
);
512 outb(0x20, VGA_ATT_IW
);
517 static int vga16fb_set_var(struct fb_var_screeninfo
*var
, int con
,
520 struct vga16fb_info
*info
= (struct vga16fb_info
*)fb
;
521 struct vga16fb_par par
;
522 struct display
*display
;
528 display
= fb_display
+ con
;
529 if ((err
= vga16fb_decode_var(var
, &par
, info
)) != 0)
531 vga16fb_encode_var(var
, &par
, info
);
533 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_TEST
)
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
;
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
);
555 vga16fb_set_par(&par
, info
);
561 static void ega16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
563 static unsigned char map
[] = { 000, 001, 010, 011 };
566 val
= map
[red
>>14] | ((map
[green
>>14]) << 1) | ((map
[blue
>>14]) << 2);
567 inb_p(0x3DA); /* ! 0x3BA */
568 outb_p(regno
, 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.
586 *red
= palette
[regno
].red
;
587 *green
= palette
[regno
].green
;
588 *blue
= palette
[regno
].blue
;
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
)
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.
617 palette
[regno
].red
= red
;
618 palette
[regno
].green
= green
;
619 palette
[regno
].blue
= blue
;
622 gray
= disp
.var
.grayscale
;
624 gray
= fb_display
[currcon
].var
.grayscale
;
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
);
632 ega16_setpalette(regno
,red
,green
,blue
);
637 static void do_install_cmap(int con
, struct fb_info
*info
)
641 if (fb_display
[con
].cmap
.len
)
642 fb_set_cmap(&fb_display
[con
].cmap
, 1, vga16_setcolreg
, info
);
644 fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg
,
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);
656 fb_copy_cmap(fb_default_cmap(16),
661 static int vga16fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
662 struct fb_info
*info
)
666 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
667 err
= fb_alloc_cmap(&fb_display
[con
].cmap
,16,0);
671 if (con
== currcon
) /* current console? */
672 return fb_set_cmap(cmap
, kspc
, vga16_setcolreg
, info
);
674 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
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
)
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
;
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
)
699 static struct fb_ops vga16fb_ops
= {
711 int vga16fb_setup(char *options
)
715 vga16fb
.fb_info
.fontname
[0] = '\0';
717 if (!options
|| !*options
)
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);
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
,
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); */
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
;
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
);
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 */
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
);
840 static void vga_vesa_unblank(struct vga16fb_info
*info
)
842 unsigned char SeqCtrlIndex
;
843 unsigned char CrtCtrlIndex
;
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
);
877 static void vga_pal_blank(void)
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
;
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;
907 info
->palette_blanked
= 1;
909 default: /* VESA blanking */
910 vga_vesa_blank(info
, blank
-1);
911 info
->vesa_blanked
= 1;
916 int __init
vga16_init(void)
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
++) {
936 palette
[i
].red
= default_red
[j
];
937 palette
[i
].green
= default_grn
[j
];
938 palette
[i
].blue
= default_blu
[j
];
941 request_region(0x3c0, 32, "vga+");
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)
962 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
963 GET_FB_IDX(vga16fb
.fb_info
.node
), vga16fb
.fb_info
.modename
);
969 int __init
vga16fb_init(void)
976 int init_module(void)
981 void cleanup_module(void)
983 unregister_framebuffer(&vga16fb
.fb_info
);
984 release_region(0x3c0, 32);
985 iounmap(vga16fb
.video_vbase
);
991 * Overrides for Emacs so that we follow Linus's tabbing style.
992 * ---------------------------------------------------------------------------