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>
33 /* --------------------------------------------------------------------- */
40 /* structure holding original VGA register settings when the
43 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
44 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
45 unsigned char CrtMiscIO; /* Miscellaneous register */
46 unsigned char HorizontalTotal; /* CRT-Controller:00h */
47 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
48 unsigned char StartHorizRetrace;/* CRT-Controller:04h */
49 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
50 unsigned char Overflow; /* CRT-Controller:07h */
51 unsigned char StartVertRetrace; /* CRT-Controller:10h */
52 unsigned char EndVertRetrace; /* CRT-Controller:11h */
53 unsigned char ModeControl; /* CRT-Controller:17h */
54 unsigned char ClockingMode; /* Seq-Controller:01h */
56 struct vgastate state;
57 unsigned int ref_count;
58 int palette_blanked, vesa_blanked, mode, isVGA;
59 u8 misc, pel_msk, vss, clkdiv;
63 /* --------------------------------------------------------------------- */
65 static struct fb_var_screeninfo vga16fb_defined = {
71 .activate = FB_ACTIVATE_TEST,
81 .vmode = FB_VMODE_NONINTERLACED,
84 /* name should not depend on EGA/VGA */
85 static const struct fb_fix_screeninfo vga16fb_fix = {
87 .smem_start = VGA_FB_PHYS_BASE,
88 .smem_len = VGA_FB_PHYS_SIZE,
89 .type = FB_TYPE_VGA_PLANES,
90 .type_aux = FB_AUX_VGA_PLANES_VGA4,
91 .visual = FB_VISUAL_PSEUDOCOLOR,
94 .line_length = 640 / 8,
95 .accel = FB_ACCEL_NONE
98 /* The VGA's weird architecture often requires that we read a byte and
99 write a byte to the same location. It doesn't matter *what* byte
100 we write, however. This is because all the action goes on behind
101 the scenes in the VGA's 32-bit latch register, and reading and writing
102 video memory just invokes latch behavior.
104 To avoid race conditions (is this necessary?), reading and writing
105 the memory byte should be done with a single instruction. One
106 suitable instruction is the x86 bitwise OR. The following
107 read-modify-write routine should optimize to one such bitwise
109 static inline void rmw(volatile char __iomem *p)
115 /* Set the Graphics Mode Register, and return its previous value.
116 Bits 0-1 are write mode, bit 3 is read mode. */
117 static inline int setmode(int mode)
121 oldmode = vga_io_rgfx(VGA_GFX_MODE);
122 vga_io_w(VGA_GFX_D, mode);
126 /* Select the Bit Mask Register and return its value. */
127 static inline int selectmask(void)
129 return vga_io_rgfx(VGA_GFX_BIT_MASK);
132 /* Set the value of the Bit Mask Register. It must already have been
133 selected with selectmask(). */
134 static inline void setmask(int mask)
136 vga_io_w(VGA_GFX_D, mask);
139 /* Set the Data Rotate Register and return its old value.
140 Bits 0-2 are rotate count, bits 3-4 are logical operation
141 (0=NOP, 1=AND, 2=OR, 3=XOR). */
142 static inline int setop(int op)
146 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
147 vga_io_w(VGA_GFX_D, op);
151 /* Set the Enable Set/Reset Register and return its old value.
152 The code here always uses value 0xf for this register. */
153 static inline int setsr(int sr)
157 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
158 vga_io_w(VGA_GFX_D, sr);
162 /* Set the Set/Reset Register and return its old value. */
163 static inline int setcolor(int color)
167 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
168 vga_io_w(VGA_GFX_D, color);
172 /* Return the value in the Graphics Address Register. */
173 static inline int getindex(void)
175 return vga_io_r(VGA_GFX_I);
178 /* Set the value in the Graphics Address Register. */
179 static inline void setindex(int index)
181 vga_io_w(VGA_GFX_I, index);
184 /* Check if the video mode is supported by the driver */
185 static inline int check_mode_supported(const struct screen_info *si)
187 /* non-x86 architectures treat orig_video_isVGA as a boolean flag */
188 #if defined(CONFIG_X86)
189 /* only EGA and VGA in 16 color graphic mode are supported */
190 if (si->orig_video_isVGA != VIDEO_TYPE_EGAC &&
191 si->orig_video_isVGA != VIDEO_TYPE_VGAC)
194 if (si->orig_video_mode != 0x0D && /* 320x200/4 (EGA) */
195 si->orig_video_mode != 0x0E && /* 640x200/4 (EGA) */
196 si->orig_video_mode != 0x10 && /* 640x350/4 (EGA) */
197 si->orig_video_mode != 0x12) /* 640x480/4 (VGA) */
203 static void vga16fb_pan_var(struct fb_info *info,
204 struct fb_var_screeninfo *var)
206 struct vga16fb_par *par = info->par;
209 xoffset = var->xoffset;
210 if (info->var.bits_per_pixel == 8) {
211 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
212 } else if (par->mode & MODE_TEXT) {
213 int fh = 16; // FIXME !!! font height. Fugde for now.
214 pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
216 if (info->var.nonstd)
218 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
220 vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
221 vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
222 /* if we support CFB4, then we must! support xoffset with pixel
223 * granularity if someone supports xoffset in bit resolution */
224 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
225 vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
226 if (info->var.bits_per_pixel == 8)
227 vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
229 vga_io_w(VGA_ATT_IW, xoffset & 7);
230 vga_io_r(VGA_IS1_RC);
231 vga_io_w(VGA_ATT_IW, 0x20);
234 static void vga16fb_update_fix(struct fb_info *info)
236 if (info->var.bits_per_pixel == 4) {
237 if (info->var.nonstd) {
238 info->fix.type = FB_TYPE_PACKED_PIXELS;
239 info->fix.line_length = info->var.xres_virtual / 2;
241 info->fix.type = FB_TYPE_VGA_PLANES;
242 info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
243 info->fix.line_length = info->var.xres_virtual / 8;
245 } else if (info->var.bits_per_pixel == 0) {
246 info->fix.type = FB_TYPE_TEXT;
247 info->fix.type_aux = FB_AUX_TEXT_CGA;
248 info->fix.line_length = info->var.xres_virtual / 4;
250 if (info->var.nonstd) {
251 info->fix.type = FB_TYPE_VGA_PLANES;
252 info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
253 info->fix.line_length = info->var.xres_virtual / 4;
255 info->fix.type = FB_TYPE_PACKED_PIXELS;
256 info->fix.line_length = info->var.xres_virtual;
261 static void vga16fb_clock_chip(struct vga16fb_par *par,
262 unsigned int *pixclock,
263 const struct fb_info *info,
266 static const struct {
270 } *ptr, *best, vgaclocks[] = {
271 { 79442 /* 12.587 */, 0x00, 0x08},
272 { 70616 /* 14.161 */, 0x04, 0x08},
273 { 39721 /* 25.175 */, 0x00, 0x00},
274 { 35308 /* 28.322 */, 0x04, 0x00},
275 { 0 /* bad */, 0x00, 0x00}};
278 *pixclock = (*pixclock * mul) / div;
280 err = *pixclock - best->pixclock;
281 if (err < 0) err = -err;
282 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
285 tmp = *pixclock - ptr->pixclock;
286 if (tmp < 0) tmp = -tmp;
292 par->misc |= best->misc;
293 par->clkdiv = best->seq_clock_mode;
294 *pixclock = (best->pixclock * div) / mul;
297 #define FAIL(X) return -EINVAL
299 static int vga16fb_open(struct fb_info *info, int user)
301 struct vga16fb_par *par = info->par;
303 if (!par->ref_count) {
304 memset(&par->state, 0, sizeof(struct vgastate));
305 par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
307 save_vga(&par->state);
314 static int vga16fb_release(struct fb_info *info, int user)
316 struct vga16fb_par *par = info->par;
321 if (par->ref_count == 1)
322 restore_vga(&par->state);
328 static int vga16fb_check_var(struct fb_var_screeninfo *var,
329 struct fb_info *info)
331 struct vga16fb_par *par = info->par;
332 u32 xres, right, hslen, left, xtotal;
333 u32 yres, lower, vslen, upper, ytotal;
334 u32 vxres, xoffset, vyres, yoffset;
343 if (var->bits_per_pixel == 4) {
348 mode = MODE_SKIP4 | MODE_CFB;
356 } else if (var->bits_per_pixel == 8) {
358 return -EINVAL; /* no support on EGA */
361 mode = MODE_8BPP | MODE_CFB;
364 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
370 xres = (var->xres + 7) & ~7;
371 vxres = (var->xres_virtual + 0xF) & ~0xF;
372 xoffset = (var->xoffset + 7) & ~7;
373 left = (var->left_margin + 7) & ~7;
374 right = (var->right_margin + 7) & ~7;
375 hslen = (var->hsync_len + 7) & ~7;
379 if (xres + xoffset > vxres)
380 xoffset = vxres - xres;
383 var->right_margin = right;
384 var->hsync_len = hslen;
385 var->left_margin = left;
386 var->xres_virtual = vxres;
387 var->xoffset = xoffset;
394 xtotal = xres + right + hslen + left;
396 FAIL("xtotal too big");
398 FAIL("hslen too big");
399 if (right + hslen + left > 64)
400 FAIL("hblank too big");
401 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
402 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
403 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
405 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
407 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
408 pos += left - 2; /* blank_end + 2 <= total + 5 */
409 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
411 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
414 lower = var->lower_margin;
415 vslen = var->vsync_len;
416 upper = var->upper_margin;
417 vyres = var->yres_virtual;
418 yoffset = var->yoffset;
422 if (vxres * vyres > maxmem) {
423 vyres = maxmem / vxres;
427 if (yoffset + yres > vyres)
428 yoffset = vyres - yres;
430 var->lower_margin = lower;
431 var->vsync_len = vslen;
432 var->upper_margin = upper;
433 var->yres_virtual = vyres;
434 var->yoffset = yoffset;
436 if (var->vmode & FB_VMODE_DOUBLE) {
442 ytotal = yres + lower + vslen + upper;
453 FAIL("ytotal too big");
455 FAIL("vslen too big");
456 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
457 r7 = 0x10; /* disable linecompare */
458 if (ytotal & 0x100) r7 |= 0x01;
459 if (ytotal & 0x200) r7 |= 0x20;
460 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
461 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
462 if (var->vmode & FB_VMODE_DOUBLE)
463 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
464 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
465 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
466 if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
468 pos = yoffset * vxres + (xoffset >> shift);
469 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
470 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
471 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
472 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
474 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
475 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
477 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
479 r7 |= 0x40; /* 0x40 -> DISP_END */
480 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
483 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
489 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
490 pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
491 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
492 but some SVGA chips requires all 8 bits to set */
494 FAIL("vxres too long");
495 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
496 if (mode & MODE_SKIP4)
497 par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */
499 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */
500 par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
501 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
502 par->crtc[VGA_CRTC_OVERFLOW] = r7;
504 par->vss = 0x00; /* 3DA */
506 par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
507 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
509 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
514 if (mode & MODE_8BPP)
515 /* pixel clock == vga clock / 2 */
516 vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
518 /* pixel clock == vga clock */
519 vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
521 var->red.offset = var->green.offset = var->blue.offset =
522 var->transp.offset = 0;
523 var->red.length = var->green.length = var->blue.length =
524 (par->isVGA) ? 6 : 2;
525 var->transp.length = 0;
526 var->activate = FB_ACTIVATE_NOW;
529 var->accel_flags = 0;
534 static int vga16fb_set_par(struct fb_info *info)
536 struct vga16fb_par *par = info->par;
542 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
543 if (par->mode & MODE_TEXT)
544 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
546 seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
547 seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
548 if (par->mode & MODE_TEXT)
549 seq[VGA_SEQ_MEMORY_MODE] = 0x03;
550 else if (par->mode & MODE_SKIP4)
551 seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
553 seq[VGA_SEQ_MEMORY_MODE] = 0x06;
555 gdc[VGA_GFX_SR_VALUE] = 0x00;
556 gdc[VGA_GFX_SR_ENABLE] = 0x00;
557 gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
558 gdc[VGA_GFX_DATA_ROTATE] = 0x00;
559 gdc[VGA_GFX_PLANE_READ] = 0;
560 if (par->mode & MODE_TEXT) {
561 gdc[VGA_GFX_MODE] = 0x10;
562 gdc[VGA_GFX_MISC] = 0x06;
564 if (par->mode & MODE_CFB)
565 gdc[VGA_GFX_MODE] = 0x40;
567 gdc[VGA_GFX_MODE] = 0x00;
568 gdc[VGA_GFX_MISC] = 0x05;
570 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
571 gdc[VGA_GFX_BIT_MASK] = 0xFF;
573 for (i = 0x00; i < 0x10; i++)
575 if (par->mode & MODE_TEXT)
576 atc[VGA_ATC_MODE] = 0x04;
577 else if (par->mode & MODE_8BPP)
578 atc[VGA_ATC_MODE] = 0x41;
580 atc[VGA_ATC_MODE] = 0x81;
581 atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
582 atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
583 if (par->mode & MODE_8BPP)
584 atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
586 atc[VGA_ATC_PEL] = info->var.xoffset & 7;
587 atc[VGA_ATC_COLOR_PAGE] = 0x00;
589 if (par->mode & MODE_TEXT) {
590 fh = 16; // FIXME !!! Fudge font height.
591 par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
595 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
597 /* Enable graphics register modification */
599 vga_io_w(EGA_GFX_E0, 0x00);
600 vga_io_w(EGA_GFX_E1, 0x01);
603 /* update misc output register */
604 vga_io_w(VGA_MIS_W, par->misc);
606 /* synchronous reset on */
607 vga_io_wseq(0x00, 0x01);
610 vga_io_w(VGA_PEL_MSK, par->pel_msk);
612 /* write sequencer registers */
613 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
614 for (i = 2; i < VGA_SEQ_C; i++) {
615 vga_io_wseq(i, seq[i]);
618 /* synchronous reset off */
619 vga_io_wseq(0x00, 0x03);
621 /* deprotect CRT registers 0-7 */
622 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
624 /* write CRT registers */
625 for (i = 0; i < VGA_CRTC_REGS; i++) {
626 vga_io_wcrt(i, par->crtc[i]);
629 /* write graphics controller registers */
630 for (i = 0; i < VGA_GFX_C; i++) {
631 vga_io_wgfx(i, gdc[i]);
634 /* write attribute controller registers */
635 for (i = 0; i < VGA_ATT_C; i++) {
636 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
637 vga_io_wattr(i, atc[i]);
640 /* Wait for screen to stabilize. */
643 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
645 vga_io_r(VGA_IS1_RC);
646 vga_io_w(VGA_ATT_IW, 0x20);
648 vga16fb_update_fix(info);
652 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
654 static const unsigned char map[] = { 000, 001, 010, 011 };
659 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
660 vga_io_r(VGA_IS1_RC); /* ! 0x3BA */
661 vga_io_wattr(regno, val);
662 vga_io_r(VGA_IS1_RC); /* some clones need it */
663 vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
666 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
668 outb(regno, VGA_PEL_IW);
669 outb(red >> 10, VGA_PEL_D);
670 outb(green >> 10, VGA_PEL_D);
671 outb(blue >> 10, VGA_PEL_D);
674 static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
675 unsigned blue, unsigned transp,
676 struct fb_info *info)
678 struct vga16fb_par *par = info->par;
682 * Set a single color register. The values supplied are
683 * already rounded down to the hardware's capabilities
684 * (according to the entries in the `var' structure). Return
685 * != 0 for invalid regno.
691 gray = info->var.grayscale;
694 /* gray = 0.30*R + 0.59*G + 0.11*B */
695 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
698 vga16_setpalette(regno,red,green,blue);
700 ega16_setpalette(regno,red,green,blue);
704 static int vga16fb_pan_display(struct fb_var_screeninfo *var,
705 struct fb_info *info)
707 vga16fb_pan_var(info, var);
711 /* The following VESA blanking code is taken from vgacon.c. The VGA
712 blanking code was originally by Huang shi chao, and modified by
713 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
714 (tjd@barefoot.org) for Linux. */
716 static void vga_vesa_blank(struct vga16fb_par *par, int mode)
718 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
719 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
721 /* save original values of VGA controller registers */
722 if(!par->vesa_blanked) {
723 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
726 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
727 par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */
728 par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */
729 par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */
730 par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */
731 par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */
732 par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */
733 par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
734 par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */
737 /* assure that video is enabled */
738 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
739 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
741 /* test for vertical retrace in process.... */
742 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
743 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
746 * Set <End of vertical retrace> to minimum (0) and
747 * <Start of vertical Retrace> to maximum (incl. overflow)
748 * Result: turn off vertical sync (VSync) pulse.
750 if (mode & FB_BLANK_VSYNC_SUSPEND) {
751 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
752 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
753 /* bits 9,10 of vert. retrace */
754 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
757 if (mode & FB_BLANK_HSYNC_SUSPEND) {
759 * Set <End of horizontal retrace> to minimum (0) and
760 * <Start of horizontal Retrace> to maximum
761 * Result: turn off horizontal sync (HSync) pulse.
763 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
764 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
767 /* restore both index registers */
768 outb_p(SeqCtrlIndex, VGA_SEQ_I);
769 outb_p(CrtCtrlIndex, VGA_CRT_IC);
772 static void vga_vesa_unblank(struct vga16fb_par *par)
774 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
775 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
777 /* restore original values of VGA controller registers */
778 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
780 /* HorizontalTotal */
781 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
782 /* HorizDisplayEnd */
783 vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
784 /* StartHorizRetrace */
785 vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
786 /* EndHorizRetrace */
787 vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
789 vga_io_wcrt(0x07, par->vga_state.Overflow);
790 /* StartVertRetrace */
791 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
793 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
795 vga_io_wcrt(0x17, par->vga_state.ModeControl);
797 vga_io_wseq(0x01, par->vga_state.ClockingMode);
799 /* restore index/control registers */
800 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
801 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
804 static void vga_pal_blank(void)
808 for (i=0; i<16; i++) {
809 outb_p(i, VGA_PEL_IW);
810 outb_p(0, VGA_PEL_D);
811 outb_p(0, VGA_PEL_D);
812 outb_p(0, VGA_PEL_D);
816 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
817 static int vga16fb_blank(int blank, struct fb_info *info)
819 struct vga16fb_par *par = info->par;
822 case FB_BLANK_UNBLANK: /* Unblank */
823 if (par->vesa_blanked) {
824 vga_vesa_unblank(par);
825 par->vesa_blanked = 0;
827 if (par->palette_blanked) {
828 par->palette_blanked = 0;
831 case FB_BLANK_NORMAL: /* blank */
833 par->palette_blanked = 1;
835 default: /* VESA blanking */
836 vga_vesa_blank(par, blank);
837 par->vesa_blanked = 1;
843 static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
845 u32 dx = rect->dx, width = rect->width;
846 char oldindex = getindex();
847 char oldmode = setmode(0x40);
848 char oldmask = selectmask();
849 int line_ofs, height;
854 where = info->screen_base + dx + rect->dy * info->fix.line_length;
856 if (rect->rop == ROP_COPY) {
861 line_ofs = info->fix.line_length - width;
864 height = rect->height;
869 /* we can do memset... */
870 for (x = width; x > 0; --x) {
871 writeb(rect->color, where);
877 char oldcolor = setcolor(0xf);
883 for (y = 0; y < rect->height; y++) {
886 where += info->fix.line_length;
897 static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
899 int x, x2, y2, vxres, vyres, width, height, line_ofs;
902 vxres = info->var.xres_virtual;
903 vyres = info->var.yres_virtual;
905 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
908 /* We could use hardware clipping but on many cards you get around
909 * hardware clipping by writing to framebuffer directly. */
911 x2 = rect->dx + rect->width;
912 y2 = rect->dy + rect->height;
913 x2 = x2 < vxres ? x2 : vxres;
914 y2 = y2 < vyres ? y2 : vyres;
915 width = x2 - rect->dx;
917 switch (info->fix.type) {
918 case FB_TYPE_VGA_PLANES:
919 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
921 height = y2 - rect->dy;
922 width = rect->width/8;
924 line_ofs = info->fix.line_length - width;
925 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
932 setcolor(rect->color);
938 for (x = 0; x < width; x++) {
954 for (x = 0; x < width; x++) {
963 vga_8planes_fillrect(info, rect);
965 case FB_TYPE_PACKED_PIXELS:
967 cfb_fillrect(info, rect);
972 static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
974 char oldindex = getindex();
975 char oldmode = setmode(0x41);
976 char oldop = setop(0);
977 char oldsr = setsr(0xf);
978 int height, line_ofs, x;
983 height = area->height;
987 width = area->width / 4;
989 if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
990 line_ofs = info->fix.line_length - width;
991 dest = info->screen_base + dx + area->dy * info->fix.line_length;
992 src = info->screen_base + sx + area->sy * info->fix.line_length;
994 for (x = 0; x < width; x++) {
1004 line_ofs = info->fix.line_length - width;
1005 dest = info->screen_base + dx + width +
1006 (area->dy + height - 1) * info->fix.line_length;
1007 src = info->screen_base + sx + width +
1008 (area->sy + height - 1) * info->fix.line_length;
1010 for (x = 0; x < width; x++) {
1027 static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1029 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1030 int x, x2, y2, old_dx, old_dy, vxres, vyres;
1031 int height, width, line_ofs;
1032 char __iomem *dst = NULL;
1033 char __iomem *src = NULL;
1035 vxres = info->var.xres_virtual;
1036 vyres = info->var.yres_virtual;
1038 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1042 /* clip the destination */
1047 * We could use hardware clipping but on many cards you get around
1048 * hardware clipping by writing to framebuffer directly.
1050 x2 = area->dx + area->width;
1051 y2 = area->dy + area->height;
1052 dx = area->dx > 0 ? area->dx : 0;
1053 dy = area->dy > 0 ? area->dy : 0;
1054 x2 = x2 < vxres ? x2 : vxres;
1055 y2 = y2 < vyres ? y2 : vyres;
1059 if (sx + dx < old_dx || sy + dy < old_dy)
1062 /* update sx1,sy1 */
1063 sx += (dx - old_dx);
1064 sy += (dy - old_dy);
1066 /* the source must be completely inside the virtual screen */
1067 if (sx + width > vxres || sy + height > vyres)
1070 switch (info->fix.type) {
1071 case FB_TYPE_VGA_PLANES:
1072 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1074 line_ofs = info->fix.line_length - width;
1080 if (dy < sy || (dy == sy && dx < sx)) {
1081 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1082 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1084 for (x = 0; x < width; x++) {
1094 dst = info->screen_base + (dx/8) + width +
1095 (dy + height - 1) * info->fix.line_length;
1096 src = info->screen_base + (sx/8) + width +
1097 (sy + height - 1) * info->fix.line_length;
1099 for (x = 0; x < width; x++) {
1110 vga_8planes_copyarea(info, area);
1112 case FB_TYPE_PACKED_PIXELS:
1114 cfb_copyarea(info, area);
1119 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1120 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1121 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1123 #if defined(__LITTLE_ENDIAN)
1124 static const u16 transl_l[] = TRANS_MASK_LOW;
1125 static const u16 transl_h[] = TRANS_MASK_HIGH;
1126 #elif defined(__BIG_ENDIAN)
1127 static const u16 transl_l[] = TRANS_MASK_HIGH;
1128 static const u16 transl_h[] = TRANS_MASK_LOW;
1130 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1133 static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1135 char oldindex = getindex();
1136 char oldmode = setmode(0x40);
1137 char oldop = setop(0);
1138 char oldsr = setsr(0);
1139 char oldmask = selectmask();
1140 const unsigned char *cdat = image->data;
1142 char __iomem *where;
1146 where = info->screen_base + dx + image->dy * info->fix.line_length;
1149 writeb(image->bg_color, where);
1152 setmask(image->fg_color ^ image->bg_color);
1155 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1156 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1164 static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1166 char __iomem *where = info->screen_base + (image->dx/8) +
1167 image->dy * info->fix.line_length;
1168 struct vga16fb_par *par = info->par;
1169 char *cdat = (char *) image->data;
1173 switch (info->fix.type) {
1174 case FB_TYPE_VGA_PLANES:
1175 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1180 setcolor(image->fg_color);
1184 writeb(image->bg_color, where);
1186 readb(where); /* fill latches */
1189 for (y = 0; y < image->height; y++) {
1191 for (x = image->width/8; x--;)
1192 writeb(*cdat++, dst++);
1193 where += info->fix.line_length;
1200 setcolor(image->bg_color);
1204 for (y = 0; y < image->height; y++) {
1206 for (x=image->width/8; x--;){
1208 setcolor(image->fg_color);
1215 where += info->fix.line_length;
1219 vga_8planes_imageblit(info, image);
1221 case FB_TYPE_PACKED_PIXELS:
1223 cfb_imageblit(info, image);
1228 static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1233 struct vga16fb_par *par = info->par;
1234 char __iomem *where =
1235 info->screen_base + image->dy * info->fix.line_length +
1237 const char *cdat = image->data;
1241 switch (info->fix.type) {
1242 case FB_TYPE_VGA_PLANES:
1243 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1249 for (y = 0; y < image->height; y++) {
1250 for (x = 0; x < image->width; x++) {
1255 setmask(1 << (7 - (x % 8)));
1261 where += info->fix.line_length;
1265 case FB_TYPE_PACKED_PIXELS:
1266 cfb_imageblit(info, image);
1273 static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1275 if (image->depth == 1)
1276 vga_imageblit_expand(info, image);
1278 vga_imageblit_color(info, image);
1281 static void vga16fb_destroy(struct fb_info *info)
1283 iounmap(info->screen_base);
1284 fb_dealloc_cmap(&info->cmap);
1285 /* XXX unshare VGA regions */
1286 framebuffer_release(info);
1289 static const struct fb_ops vga16fb_ops = {
1290 .owner = THIS_MODULE,
1291 .fb_open = vga16fb_open,
1292 .fb_release = vga16fb_release,
1293 .fb_destroy = vga16fb_destroy,
1294 .fb_check_var = vga16fb_check_var,
1295 .fb_set_par = vga16fb_set_par,
1296 .fb_setcolreg = vga16fb_setcolreg,
1297 .fb_pan_display = vga16fb_pan_display,
1298 .fb_blank = vga16fb_blank,
1299 .fb_fillrect = vga16fb_fillrect,
1300 .fb_copyarea = vga16fb_copyarea,
1301 .fb_imageblit = vga16fb_imageblit,
1304 static int vga16fb_probe(struct platform_device *dev)
1306 struct screen_info *si;
1307 struct fb_info *info;
1308 struct vga16fb_par *par;
1312 si = dev_get_platdata(&dev->dev);
1316 ret = check_mode_supported(si);
1320 printk(KERN_DEBUG "vga16fb: initializing\n");
1321 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1327 info->apertures = alloc_apertures(1);
1328 if (!info->apertures) {
1333 /* XXX share VGA_FB_PHYS_BASE and I/O region with vgacon and others */
1334 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS_BASE, 0);
1336 if (!info->screen_base) {
1337 printk(KERN_ERR "vga16fb: unable to map device\n");
1342 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1345 #if defined(CONFIG_X86)
1346 par->isVGA = si->orig_video_isVGA == VIDEO_TYPE_VGAC;
1348 /* non-x86 architectures treat orig_video_isVGA as a boolean flag */
1349 par->isVGA = si->orig_video_isVGA;
1351 par->palette_blanked = 0;
1352 par->vesa_blanked = 0;
1354 i = par->isVGA? 6 : 2;
1356 vga16fb_defined.red.length = i;
1357 vga16fb_defined.green.length = i;
1358 vga16fb_defined.blue.length = i;
1360 /* name should not depend on EGA/VGA */
1361 info->fbops = &vga16fb_ops;
1362 info->var = vga16fb_defined;
1363 info->fix = vga16fb_fix;
1364 /* supports rectangles with widths of multiples of 8 */
1365 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1366 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
1367 FBINFO_HWACCEL_YPAN;
1369 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1370 ret = fb_alloc_cmap(&info->cmap, i, 0);
1372 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1374 goto err_alloc_cmap;
1377 if (vga16fb_check_var(&info->var, info)) {
1378 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1383 vga16fb_update_fix(info);
1385 info->apertures->ranges[0].base = VGA_FB_PHYS_BASE;
1386 info->apertures->ranges[0].size = VGA_FB_PHYS_SIZE;
1388 if (register_framebuffer(info) < 0) {
1389 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1394 fb_info(info, "%s frame buffer device\n", info->fix.id);
1395 platform_set_drvdata(dev, info);
1400 fb_dealloc_cmap(&info->cmap);
1402 iounmap(info->screen_base);
1404 framebuffer_release(info);
1409 static int vga16fb_remove(struct platform_device *dev)
1411 struct fb_info *info = platform_get_drvdata(dev);
1414 unregister_framebuffer(info);
1419 static const struct platform_device_id vga16fb_driver_id_table[] = {
1420 {"ega-framebuffer", 0},
1421 {"vga-framebuffer", 0},
1425 static struct platform_driver vga16fb_driver = {
1426 .probe = vga16fb_probe,
1427 .remove = vga16fb_remove,
1431 .id_table = vga16fb_driver_id_table,
1434 module_platform_driver(vga16fb_driver);
1436 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1437 MODULE_LICENSE("GPL");