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.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
18 #include <linux/delay.h>
20 #include <linux/ioport.h>
21 #include <linux/init.h>
22 #include <linux/platform_device.h>
23 #include <linux/screen_info.h>
26 #include <video/vga.h>
28 #define VGA_FB_PHYS 0xA0000
29 #define VGA_FB_PHYS_LEN 65536
36 /* --------------------------------------------------------------------- */
43 /* structure holding original VGA register settings when the
46 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
47 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
48 unsigned char CrtMiscIO; /* Miscellaneous register */
49 unsigned char HorizontalTotal; /* CRT-Controller:00h */
50 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
51 unsigned char StartHorizRetrace;/* CRT-Controller:04h */
52 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
53 unsigned char Overflow; /* CRT-Controller:07h */
54 unsigned char StartVertRetrace; /* CRT-Controller:10h */
55 unsigned char EndVertRetrace; /* CRT-Controller:11h */
56 unsigned char ModeControl; /* CRT-Controller:17h */
57 unsigned char ClockingMode; /* Seq-Controller:01h */
59 struct vgastate state;
60 unsigned int ref_count;
61 int palette_blanked, vesa_blanked, mode, isVGA;
62 u8 misc, pel_msk, vss, clkdiv;
66 /* --------------------------------------------------------------------- */
68 static struct fb_var_screeninfo vga16fb_defined = {
74 .activate = FB_ACTIVATE_TEST,
84 .vmode = FB_VMODE_NONINTERLACED,
87 /* name should not depend on EGA/VGA */
88 static const struct fb_fix_screeninfo vga16fb_fix = {
90 .smem_start = VGA_FB_PHYS,
91 .smem_len = VGA_FB_PHYS_LEN,
92 .type = FB_TYPE_VGA_PLANES,
93 .type_aux = FB_AUX_VGA_PLANES_VGA4,
94 .visual = FB_VISUAL_PSEUDOCOLOR,
97 .line_length = 640 / 8,
98 .accel = FB_ACCEL_NONE
101 /* The VGA's weird architecture often requires that we read a byte and
102 write a byte to the same location. It doesn't matter *what* byte
103 we write, however. This is because all the action goes on behind
104 the scenes in the VGA's 32-bit latch register, and reading and writing
105 video memory just invokes latch behavior.
107 To avoid race conditions (is this necessary?), reading and writing
108 the memory byte should be done with a single instruction. One
109 suitable instruction is the x86 bitwise OR. The following
110 read-modify-write routine should optimize to one such bitwise
112 static inline void rmw(volatile char __iomem *p)
118 /* Set the Graphics Mode Register, and return its previous value.
119 Bits 0-1 are write mode, bit 3 is read mode. */
120 static inline int setmode(int mode)
124 oldmode = vga_io_rgfx(VGA_GFX_MODE);
125 vga_io_w(VGA_GFX_D, mode);
129 /* Select the Bit Mask Register and return its value. */
130 static inline int selectmask(void)
132 return vga_io_rgfx(VGA_GFX_BIT_MASK);
135 /* Set the value of the Bit Mask Register. It must already have been
136 selected with selectmask(). */
137 static inline void setmask(int mask)
139 vga_io_w(VGA_GFX_D, mask);
142 /* Set the Data Rotate Register and return its old value.
143 Bits 0-2 are rotate count, bits 3-4 are logical operation
144 (0=NOP, 1=AND, 2=OR, 3=XOR). */
145 static inline int setop(int op)
149 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
150 vga_io_w(VGA_GFX_D, op);
154 /* Set the Enable Set/Reset Register and return its old value.
155 The code here always uses value 0xf for this register. */
156 static inline int setsr(int sr)
160 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
161 vga_io_w(VGA_GFX_D, sr);
165 /* Set the Set/Reset Register and return its old value. */
166 static inline int setcolor(int color)
170 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
171 vga_io_w(VGA_GFX_D, color);
175 /* Return the value in the Graphics Address Register. */
176 static inline int getindex(void)
178 return vga_io_r(VGA_GFX_I);
181 /* Set the value in the Graphics Address Register. */
182 static inline void setindex(int index)
184 vga_io_w(VGA_GFX_I, index);
187 /* Check if the video mode is supported by the driver */
188 static inline int check_mode_supported(const struct screen_info *si)
190 /* non-x86 architectures treat orig_video_isVGA as a boolean flag */
191 #if defined(CONFIG_X86)
192 /* only EGA and VGA in 16 color graphic mode are supported */
193 if (si->orig_video_isVGA != VIDEO_TYPE_EGAC &&
194 si->orig_video_isVGA != VIDEO_TYPE_VGAC)
197 if (si->orig_video_mode != 0x0D && /* 320x200/4 (EGA) */
198 si->orig_video_mode != 0x0E && /* 640x200/4 (EGA) */
199 si->orig_video_mode != 0x10 && /* 640x350/4 (EGA) */
200 si->orig_video_mode != 0x12) /* 640x480/4 (VGA) */
206 static void vga16fb_pan_var(struct fb_info *info,
207 struct fb_var_screeninfo *var)
209 struct vga16fb_par *par = info->par;
212 xoffset = var->xoffset;
213 if (info->var.bits_per_pixel == 8) {
214 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
215 } else if (par->mode & MODE_TEXT) {
216 int fh = 16; // FIXME !!! font height. Fugde for now.
217 pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
219 if (info->var.nonstd)
221 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
223 vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
224 vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
225 /* if we support CFB4, then we must! support xoffset with pixel
226 * granularity if someone supports xoffset in bit resolution */
227 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
228 vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
229 if (info->var.bits_per_pixel == 8)
230 vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
232 vga_io_w(VGA_ATT_IW, xoffset & 7);
233 vga_io_r(VGA_IS1_RC);
234 vga_io_w(VGA_ATT_IW, 0x20);
237 static void vga16fb_update_fix(struct fb_info *info)
239 if (info->var.bits_per_pixel == 4) {
240 if (info->var.nonstd) {
241 info->fix.type = FB_TYPE_PACKED_PIXELS;
242 info->fix.line_length = info->var.xres_virtual / 2;
244 info->fix.type = FB_TYPE_VGA_PLANES;
245 info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
246 info->fix.line_length = info->var.xres_virtual / 8;
248 } else if (info->var.bits_per_pixel == 0) {
249 info->fix.type = FB_TYPE_TEXT;
250 info->fix.type_aux = FB_AUX_TEXT_CGA;
251 info->fix.line_length = info->var.xres_virtual / 4;
253 if (info->var.nonstd) {
254 info->fix.type = FB_TYPE_VGA_PLANES;
255 info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
256 info->fix.line_length = info->var.xres_virtual / 4;
258 info->fix.type = FB_TYPE_PACKED_PIXELS;
259 info->fix.line_length = info->var.xres_virtual;
264 static void vga16fb_clock_chip(struct vga16fb_par *par,
265 unsigned int *pixclock,
266 const struct fb_info *info,
269 static const struct {
273 } *ptr, *best, vgaclocks[] = {
274 { 79442 /* 12.587 */, 0x00, 0x08},
275 { 70616 /* 14.161 */, 0x04, 0x08},
276 { 39721 /* 25.175 */, 0x00, 0x00},
277 { 35308 /* 28.322 */, 0x04, 0x00},
278 { 0 /* bad */, 0x00, 0x00}};
281 *pixclock = (*pixclock * mul) / div;
283 err = *pixclock - best->pixclock;
284 if (err < 0) err = -err;
285 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
288 tmp = *pixclock - ptr->pixclock;
289 if (tmp < 0) tmp = -tmp;
295 par->misc |= best->misc;
296 par->clkdiv = best->seq_clock_mode;
297 *pixclock = (best->pixclock * div) / mul;
300 #define FAIL(X) return -EINVAL
302 static int vga16fb_open(struct fb_info *info, int user)
304 struct vga16fb_par *par = info->par;
306 if (!par->ref_count) {
307 memset(&par->state, 0, sizeof(struct vgastate));
308 par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
310 save_vga(&par->state);
317 static int vga16fb_release(struct fb_info *info, int user)
319 struct vga16fb_par *par = info->par;
324 if (par->ref_count == 1)
325 restore_vga(&par->state);
331 static int vga16fb_check_var(struct fb_var_screeninfo *var,
332 struct fb_info *info)
334 struct vga16fb_par *par = info->par;
335 u32 xres, right, hslen, left, xtotal;
336 u32 yres, lower, vslen, upper, ytotal;
337 u32 vxres, xoffset, vyres, yoffset;
346 if (var->bits_per_pixel == 4) {
351 mode = MODE_SKIP4 | MODE_CFB;
359 } else if (var->bits_per_pixel == 8) {
361 return -EINVAL; /* no support on EGA */
364 mode = MODE_8BPP | MODE_CFB;
367 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
373 xres = (var->xres + 7) & ~7;
374 vxres = (var->xres_virtual + 0xF) & ~0xF;
375 xoffset = (var->xoffset + 7) & ~7;
376 left = (var->left_margin + 7) & ~7;
377 right = (var->right_margin + 7) & ~7;
378 hslen = (var->hsync_len + 7) & ~7;
382 if (xres + xoffset > vxres)
383 xoffset = vxres - xres;
386 var->right_margin = right;
387 var->hsync_len = hslen;
388 var->left_margin = left;
389 var->xres_virtual = vxres;
390 var->xoffset = xoffset;
397 xtotal = xres + right + hslen + left;
399 FAIL("xtotal too big");
401 FAIL("hslen too big");
402 if (right + hslen + left > 64)
403 FAIL("hblank too big");
404 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
405 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
406 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
408 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
410 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
411 pos += left - 2; /* blank_end + 2 <= total + 5 */
412 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
414 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
417 lower = var->lower_margin;
418 vslen = var->vsync_len;
419 upper = var->upper_margin;
420 vyres = var->yres_virtual;
421 yoffset = var->yoffset;
425 if (vxres * vyres > maxmem) {
426 vyres = maxmem / vxres;
430 if (yoffset + yres > vyres)
431 yoffset = vyres - yres;
433 var->lower_margin = lower;
434 var->vsync_len = vslen;
435 var->upper_margin = upper;
436 var->yres_virtual = vyres;
437 var->yoffset = yoffset;
439 if (var->vmode & FB_VMODE_DOUBLE) {
445 ytotal = yres + lower + vslen + upper;
456 FAIL("ytotal too big");
458 FAIL("vslen too big");
459 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
460 r7 = 0x10; /* disable linecompare */
461 if (ytotal & 0x100) r7 |= 0x01;
462 if (ytotal & 0x200) r7 |= 0x20;
463 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
464 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
465 if (var->vmode & FB_VMODE_DOUBLE)
466 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
467 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
468 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
469 if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
471 pos = yoffset * vxres + (xoffset >> shift);
472 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
473 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
474 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
475 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
477 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
478 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
480 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
482 r7 |= 0x40; /* 0x40 -> DISP_END */
483 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
486 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
492 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
493 pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
494 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
495 but some SVGA chips requires all 8 bits to set */
497 FAIL("vxres too long");
498 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
499 if (mode & MODE_SKIP4)
500 par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */
502 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */
503 par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
504 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
505 par->crtc[VGA_CRTC_OVERFLOW] = r7;
507 par->vss = 0x00; /* 3DA */
509 par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
510 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
512 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
517 if (mode & MODE_8BPP)
518 /* pixel clock == vga clock / 2 */
519 vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
521 /* pixel clock == vga clock */
522 vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
524 var->red.offset = var->green.offset = var->blue.offset =
525 var->transp.offset = 0;
526 var->red.length = var->green.length = var->blue.length =
527 (par->isVGA) ? 6 : 2;
528 var->transp.length = 0;
529 var->activate = FB_ACTIVATE_NOW;
532 var->accel_flags = 0;
537 static int vga16fb_set_par(struct fb_info *info)
539 struct vga16fb_par *par = info->par;
545 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
546 if (par->mode & MODE_TEXT)
547 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
549 seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
550 seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
551 if (par->mode & MODE_TEXT)
552 seq[VGA_SEQ_MEMORY_MODE] = 0x03;
553 else if (par->mode & MODE_SKIP4)
554 seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
556 seq[VGA_SEQ_MEMORY_MODE] = 0x06;
558 gdc[VGA_GFX_SR_VALUE] = 0x00;
559 gdc[VGA_GFX_SR_ENABLE] = 0x00;
560 gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
561 gdc[VGA_GFX_DATA_ROTATE] = 0x00;
562 gdc[VGA_GFX_PLANE_READ] = 0;
563 if (par->mode & MODE_TEXT) {
564 gdc[VGA_GFX_MODE] = 0x10;
565 gdc[VGA_GFX_MISC] = 0x06;
567 if (par->mode & MODE_CFB)
568 gdc[VGA_GFX_MODE] = 0x40;
570 gdc[VGA_GFX_MODE] = 0x00;
571 gdc[VGA_GFX_MISC] = 0x05;
573 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
574 gdc[VGA_GFX_BIT_MASK] = 0xFF;
576 for (i = 0x00; i < 0x10; i++)
578 if (par->mode & MODE_TEXT)
579 atc[VGA_ATC_MODE] = 0x04;
580 else if (par->mode & MODE_8BPP)
581 atc[VGA_ATC_MODE] = 0x41;
583 atc[VGA_ATC_MODE] = 0x81;
584 atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
585 atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
586 if (par->mode & MODE_8BPP)
587 atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
589 atc[VGA_ATC_PEL] = info->var.xoffset & 7;
590 atc[VGA_ATC_COLOR_PAGE] = 0x00;
592 if (par->mode & MODE_TEXT) {
593 fh = 16; // FIXME !!! Fudge font height.
594 par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
598 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
600 /* Enable graphics register modification */
602 vga_io_w(EGA_GFX_E0, 0x00);
603 vga_io_w(EGA_GFX_E1, 0x01);
606 /* update misc output register */
607 vga_io_w(VGA_MIS_W, par->misc);
609 /* synchronous reset on */
610 vga_io_wseq(0x00, 0x01);
613 vga_io_w(VGA_PEL_MSK, par->pel_msk);
615 /* write sequencer registers */
616 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
617 for (i = 2; i < VGA_SEQ_C; i++) {
618 vga_io_wseq(i, seq[i]);
621 /* synchronous reset off */
622 vga_io_wseq(0x00, 0x03);
624 /* deprotect CRT registers 0-7 */
625 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
627 /* write CRT registers */
628 for (i = 0; i < VGA_CRTC_REGS; i++) {
629 vga_io_wcrt(i, par->crtc[i]);
632 /* write graphics controller registers */
633 for (i = 0; i < VGA_GFX_C; i++) {
634 vga_io_wgfx(i, gdc[i]);
637 /* write attribute controller registers */
638 for (i = 0; i < VGA_ATT_C; i++) {
639 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
640 vga_io_wattr(i, atc[i]);
643 /* Wait for screen to stabilize. */
646 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
648 vga_io_r(VGA_IS1_RC);
649 vga_io_w(VGA_ATT_IW, 0x20);
651 vga16fb_update_fix(info);
655 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
657 static const unsigned char map[] = { 000, 001, 010, 011 };
662 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
663 vga_io_r(VGA_IS1_RC); /* ! 0x3BA */
664 vga_io_wattr(regno, val);
665 vga_io_r(VGA_IS1_RC); /* some clones need it */
666 vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
669 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
671 outb(regno, VGA_PEL_IW);
672 outb(red >> 10, VGA_PEL_D);
673 outb(green >> 10, VGA_PEL_D);
674 outb(blue >> 10, VGA_PEL_D);
677 static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
678 unsigned blue, unsigned transp,
679 struct fb_info *info)
681 struct vga16fb_par *par = info->par;
685 * Set a single color register. The values supplied are
686 * already rounded down to the hardware's capabilities
687 * (according to the entries in the `var' structure). Return
688 * != 0 for invalid regno.
694 gray = info->var.grayscale;
697 /* gray = 0.30*R + 0.59*G + 0.11*B */
698 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
701 vga16_setpalette(regno,red,green,blue);
703 ega16_setpalette(regno,red,green,blue);
707 static int vga16fb_pan_display(struct fb_var_screeninfo *var,
708 struct fb_info *info)
710 vga16fb_pan_var(info, var);
714 /* The following VESA blanking code is taken from vgacon.c. The VGA
715 blanking code was originally by Huang shi chao, and modified by
716 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
717 (tjd@barefoot.org) for Linux. */
719 static void vga_vesa_blank(struct vga16fb_par *par, int mode)
721 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
722 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
724 /* save original values of VGA controller registers */
725 if(!par->vesa_blanked) {
726 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
729 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
730 par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */
731 par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */
732 par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */
733 par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */
734 par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */
735 par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */
736 par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
737 par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */
740 /* assure that video is enabled */
741 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
742 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
744 /* test for vertical retrace in process.... */
745 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
746 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
749 * Set <End of vertical retrace> to minimum (0) and
750 * <Start of vertical Retrace> to maximum (incl. overflow)
751 * Result: turn off vertical sync (VSync) pulse.
753 if (mode & FB_BLANK_VSYNC_SUSPEND) {
754 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
755 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
756 /* bits 9,10 of vert. retrace */
757 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
760 if (mode & FB_BLANK_HSYNC_SUSPEND) {
762 * Set <End of horizontal retrace> to minimum (0) and
763 * <Start of horizontal Retrace> to maximum
764 * Result: turn off horizontal sync (HSync) pulse.
766 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
767 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
770 /* restore both index registers */
771 outb_p(SeqCtrlIndex, VGA_SEQ_I);
772 outb_p(CrtCtrlIndex, VGA_CRT_IC);
775 static void vga_vesa_unblank(struct vga16fb_par *par)
777 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
778 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
780 /* restore original values of VGA controller registers */
781 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
783 /* HorizontalTotal */
784 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
785 /* HorizDisplayEnd */
786 vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
787 /* StartHorizRetrace */
788 vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
789 /* EndHorizRetrace */
790 vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
792 vga_io_wcrt(0x07, par->vga_state.Overflow);
793 /* StartVertRetrace */
794 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
796 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
798 vga_io_wcrt(0x17, par->vga_state.ModeControl);
800 vga_io_wseq(0x01, par->vga_state.ClockingMode);
802 /* restore index/control registers */
803 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
804 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
807 static void vga_pal_blank(void)
811 for (i=0; i<16; i++) {
812 outb_p(i, VGA_PEL_IW);
813 outb_p(0, VGA_PEL_D);
814 outb_p(0, VGA_PEL_D);
815 outb_p(0, VGA_PEL_D);
819 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
820 static int vga16fb_blank(int blank, struct fb_info *info)
822 struct vga16fb_par *par = info->par;
825 case FB_BLANK_UNBLANK: /* Unblank */
826 if (par->vesa_blanked) {
827 vga_vesa_unblank(par);
828 par->vesa_blanked = 0;
830 if (par->palette_blanked) {
831 par->palette_blanked = 0;
834 case FB_BLANK_NORMAL: /* blank */
836 par->palette_blanked = 1;
838 default: /* VESA blanking */
839 vga_vesa_blank(par, blank);
840 par->vesa_blanked = 1;
846 static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
848 u32 dx = rect->dx, width = rect->width;
849 char oldindex = getindex();
850 char oldmode = setmode(0x40);
851 char oldmask = selectmask();
852 int line_ofs, height;
857 where = info->screen_base + dx + rect->dy * info->fix.line_length;
859 if (rect->rop == ROP_COPY) {
864 line_ofs = info->fix.line_length - width;
867 height = rect->height;
872 /* we can do memset... */
873 for (x = width; x > 0; --x) {
874 writeb(rect->color, where);
880 char oldcolor = setcolor(0xf);
886 for (y = 0; y < rect->height; y++) {
889 where += info->fix.line_length;
900 static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
902 int x, x2, y2, vxres, vyres, width, height, line_ofs;
905 vxres = info->var.xres_virtual;
906 vyres = info->var.yres_virtual;
908 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
911 /* We could use hardware clipping but on many cards you get around
912 * hardware clipping by writing to framebuffer directly. */
914 x2 = rect->dx + rect->width;
915 y2 = rect->dy + rect->height;
916 x2 = x2 < vxres ? x2 : vxres;
917 y2 = y2 < vyres ? y2 : vyres;
918 width = x2 - rect->dx;
920 switch (info->fix.type) {
921 case FB_TYPE_VGA_PLANES:
922 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
924 height = y2 - rect->dy;
925 width = rect->width/8;
927 line_ofs = info->fix.line_length - width;
928 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
935 setcolor(rect->color);
941 for (x = 0; x < width; x++) {
957 for (x = 0; x < width; x++) {
966 vga_8planes_fillrect(info, rect);
968 case FB_TYPE_PACKED_PIXELS:
970 cfb_fillrect(info, rect);
975 static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
977 char oldindex = getindex();
978 char oldmode = setmode(0x41);
979 char oldop = setop(0);
980 char oldsr = setsr(0xf);
981 int height, line_ofs, x;
986 height = area->height;
990 width = area->width / 4;
992 if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
993 line_ofs = info->fix.line_length - width;
994 dest = info->screen_base + dx + area->dy * info->fix.line_length;
995 src = info->screen_base + sx + area->sy * info->fix.line_length;
997 for (x = 0; x < width; x++) {
1007 line_ofs = info->fix.line_length - width;
1008 dest = info->screen_base + dx + width +
1009 (area->dy + height - 1) * info->fix.line_length;
1010 src = info->screen_base + sx + width +
1011 (area->sy + height - 1) * info->fix.line_length;
1013 for (x = 0; x < width; x++) {
1030 static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1032 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1033 int x, x2, y2, old_dx, old_dy, vxres, vyres;
1034 int height, width, line_ofs;
1035 char __iomem *dst = NULL;
1036 char __iomem *src = NULL;
1038 vxres = info->var.xres_virtual;
1039 vyres = info->var.yres_virtual;
1041 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1045 /* clip the destination */
1050 * We could use hardware clipping but on many cards you get around
1051 * hardware clipping by writing to framebuffer directly.
1053 x2 = area->dx + area->width;
1054 y2 = area->dy + area->height;
1055 dx = area->dx > 0 ? area->dx : 0;
1056 dy = area->dy > 0 ? area->dy : 0;
1057 x2 = x2 < vxres ? x2 : vxres;
1058 y2 = y2 < vyres ? y2 : vyres;
1062 if (sx + dx < old_dx || sy + dy < old_dy)
1065 /* update sx1,sy1 */
1066 sx += (dx - old_dx);
1067 sy += (dy - old_dy);
1069 /* the source must be completely inside the virtual screen */
1070 if (sx + width > vxres || sy + height > vyres)
1073 switch (info->fix.type) {
1074 case FB_TYPE_VGA_PLANES:
1075 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1077 line_ofs = info->fix.line_length - width;
1083 if (dy < sy || (dy == sy && dx < sx)) {
1084 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1085 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1087 for (x = 0; x < width; x++) {
1097 dst = info->screen_base + (dx/8) + width +
1098 (dy + height - 1) * info->fix.line_length;
1099 src = info->screen_base + (sx/8) + width +
1100 (sy + height - 1) * info->fix.line_length;
1102 for (x = 0; x < width; x++) {
1113 vga_8planes_copyarea(info, area);
1115 case FB_TYPE_PACKED_PIXELS:
1117 cfb_copyarea(info, area);
1122 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1123 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1124 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1126 #if defined(__LITTLE_ENDIAN)
1127 static const u16 transl_l[] = TRANS_MASK_LOW;
1128 static const u16 transl_h[] = TRANS_MASK_HIGH;
1129 #elif defined(__BIG_ENDIAN)
1130 static const u16 transl_l[] = TRANS_MASK_HIGH;
1131 static const u16 transl_h[] = TRANS_MASK_LOW;
1133 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1136 static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1138 char oldindex = getindex();
1139 char oldmode = setmode(0x40);
1140 char oldop = setop(0);
1141 char oldsr = setsr(0);
1142 char oldmask = selectmask();
1143 const unsigned char *cdat = image->data;
1145 char __iomem *where;
1149 where = info->screen_base + dx + image->dy * info->fix.line_length;
1152 writeb(image->bg_color, where);
1155 setmask(image->fg_color ^ image->bg_color);
1158 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1159 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1167 static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1169 char __iomem *where = info->screen_base + (image->dx/8) +
1170 image->dy * info->fix.line_length;
1171 struct vga16fb_par *par = info->par;
1172 char *cdat = (char *) image->data;
1176 switch (info->fix.type) {
1177 case FB_TYPE_VGA_PLANES:
1178 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1183 setcolor(image->fg_color);
1187 writeb(image->bg_color, where);
1189 readb(where); /* fill latches */
1192 for (y = 0; y < image->height; y++) {
1194 for (x = image->width/8; x--;)
1195 writeb(*cdat++, dst++);
1196 where += info->fix.line_length;
1203 setcolor(image->bg_color);
1207 for (y = 0; y < image->height; y++) {
1209 for (x=image->width/8; x--;){
1211 setcolor(image->fg_color);
1218 where += info->fix.line_length;
1222 vga_8planes_imageblit(info, image);
1224 case FB_TYPE_PACKED_PIXELS:
1226 cfb_imageblit(info, image);
1231 static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1236 struct vga16fb_par *par = info->par;
1237 char __iomem *where =
1238 info->screen_base + image->dy * info->fix.line_length +
1240 const char *cdat = image->data;
1244 switch (info->fix.type) {
1245 case FB_TYPE_VGA_PLANES:
1246 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1252 for (y = 0; y < image->height; y++) {
1253 for (x = 0; x < image->width; x++) {
1258 setmask(1 << (7 - (x % 8)));
1264 where += info->fix.line_length;
1268 case FB_TYPE_PACKED_PIXELS:
1269 cfb_imageblit(info, image);
1276 static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1278 if (image->depth == 1)
1279 vga_imageblit_expand(info, image);
1281 vga_imageblit_color(info, image);
1284 static void vga16fb_destroy(struct fb_info *info)
1286 iounmap(info->screen_base);
1287 fb_dealloc_cmap(&info->cmap);
1288 /* XXX unshare VGA regions */
1289 framebuffer_release(info);
1292 static const struct fb_ops vga16fb_ops = {
1293 .owner = THIS_MODULE,
1294 .fb_open = vga16fb_open,
1295 .fb_release = vga16fb_release,
1296 .fb_destroy = vga16fb_destroy,
1297 .fb_check_var = vga16fb_check_var,
1298 .fb_set_par = vga16fb_set_par,
1299 .fb_setcolreg = vga16fb_setcolreg,
1300 .fb_pan_display = vga16fb_pan_display,
1301 .fb_blank = vga16fb_blank,
1302 .fb_fillrect = vga16fb_fillrect,
1303 .fb_copyarea = vga16fb_copyarea,
1304 .fb_imageblit = vga16fb_imageblit,
1308 static int __init vga16fb_setup(char *options)
1312 if (!options || !*options)
1315 while ((this_opt = strsep(&options, ",")) != NULL) {
1316 if (!*this_opt) continue;
1322 static int vga16fb_probe(struct platform_device *dev)
1324 struct screen_info *si;
1325 struct fb_info *info;
1326 struct vga16fb_par *par;
1330 si = dev_get_platdata(&dev->dev);
1334 ret = check_mode_supported(si);
1338 printk(KERN_DEBUG "vga16fb: initializing\n");
1339 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1345 info->apertures = alloc_apertures(1);
1346 if (!info->apertures) {
1351 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1352 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1354 if (!info->screen_base) {
1355 printk(KERN_ERR "vga16fb: unable to map device\n");
1360 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1363 #if defined(CONFIG_X86)
1364 par->isVGA = si->orig_video_isVGA == VIDEO_TYPE_VGAC;
1366 /* non-x86 architectures treat orig_video_isVGA as a boolean flag */
1367 par->isVGA = si->orig_video_isVGA;
1369 par->palette_blanked = 0;
1370 par->vesa_blanked = 0;
1372 i = par->isVGA? 6 : 2;
1374 vga16fb_defined.red.length = i;
1375 vga16fb_defined.green.length = i;
1376 vga16fb_defined.blue.length = i;
1378 /* name should not depend on EGA/VGA */
1379 info->fbops = &vga16fb_ops;
1380 info->var = vga16fb_defined;
1381 info->fix = vga16fb_fix;
1382 /* supports rectangles with widths of multiples of 8 */
1383 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1384 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
1385 FBINFO_HWACCEL_YPAN;
1387 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1388 ret = fb_alloc_cmap(&info->cmap, i, 0);
1390 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1392 goto err_alloc_cmap;
1395 if (vga16fb_check_var(&info->var, info)) {
1396 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1401 vga16fb_update_fix(info);
1403 info->apertures->ranges[0].base = VGA_FB_PHYS;
1404 info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
1406 if (register_framebuffer(info) < 0) {
1407 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1412 fb_info(info, "%s frame buffer device\n", info->fix.id);
1413 platform_set_drvdata(dev, info);
1418 fb_dealloc_cmap(&info->cmap);
1420 iounmap(info->screen_base);
1422 framebuffer_release(info);
1427 static int vga16fb_remove(struct platform_device *dev)
1429 struct fb_info *info = platform_get_drvdata(dev);
1432 unregister_framebuffer(info);
1437 static const struct platform_device_id vga16fb_driver_id_table[] = {
1438 {"ega-framebuffer", 0},
1439 {"vga-framebuffer", 0},
1443 static struct platform_driver vga16fb_driver = {
1444 .probe = vga16fb_probe,
1445 .remove = vga16fb_remove,
1449 .id_table = vga16fb_driver_id_table,
1452 static int __init vga16fb_init(void)
1456 char *option = NULL;
1458 if (fb_get_options("vga16fb", &option))
1461 vga16fb_setup(option);
1464 ret = platform_driver_register(&vga16fb_driver);
1471 static void __exit vga16fb_exit(void)
1473 platform_driver_unregister(&vga16fb_driver);
1476 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1477 MODULE_LICENSE("GPL");
1478 module_init(vga16fb_init);
1479 module_exit(vga16fb_exit);