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/slab.h>
19 #include <linux/delay.h>
21 #include <linux/ioport.h>
22 #include <linux/init.h>
23 #include <linux/platform_device.h>
24 #include <linux/screen_info.h>
27 #include <video/vga.h>
29 #define VGA_FB_PHYS 0xA0000
30 #define VGA_FB_PHYS_LEN 65536
37 /* --------------------------------------------------------------------- */
44 /* structure holding original VGA register settings when the
47 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
48 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
49 unsigned char CrtMiscIO; /* Miscellaneous register */
50 unsigned char HorizontalTotal; /* CRT-Controller:00h */
51 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
52 unsigned char StartHorizRetrace;/* CRT-Controller:04h */
53 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
54 unsigned char Overflow; /* CRT-Controller:07h */
55 unsigned char StartVertRetrace; /* CRT-Controller:10h */
56 unsigned char EndVertRetrace; /* CRT-Controller:11h */
57 unsigned char ModeControl; /* CRT-Controller:17h */
58 unsigned char ClockingMode; /* Seq-Controller:01h */
60 struct vgastate state;
61 struct mutex open_lock;
62 unsigned int ref_count;
63 int palette_blanked, vesa_blanked, mode, isVGA;
64 u8 misc, pel_msk, vss, clkdiv;
68 /* --------------------------------------------------------------------- */
70 static struct fb_var_screeninfo vga16fb_defined __initdata = {
76 .activate = FB_ACTIVATE_TEST,
86 .vmode = FB_VMODE_NONINTERLACED,
89 /* name should not depend on EGA/VGA */
90 static struct fb_fix_screeninfo vga16fb_fix __initdata = {
92 .smem_start = VGA_FB_PHYS,
93 .smem_len = VGA_FB_PHYS_LEN,
94 .type = FB_TYPE_VGA_PLANES,
95 .type_aux = FB_AUX_VGA_PLANES_VGA4,
96 .visual = FB_VISUAL_PSEUDOCOLOR,
99 .line_length = 640 / 8,
100 .accel = FB_ACCEL_NONE
103 /* The VGA's weird architecture often requires that we read a byte and
104 write a byte to the same location. It doesn't matter *what* byte
105 we write, however. This is because all the action goes on behind
106 the scenes in the VGA's 32-bit latch register, and reading and writing
107 video memory just invokes latch behavior.
109 To avoid race conditions (is this necessary?), reading and writing
110 the memory byte should be done with a single instruction. One
111 suitable instruction is the x86 bitwise OR. The following
112 read-modify-write routine should optimize to one such bitwise
114 static inline void rmw(volatile char __iomem *p)
120 /* Set the Graphics Mode Register, and return its previous value.
121 Bits 0-1 are write mode, bit 3 is read mode. */
122 static inline int setmode(int mode)
126 oldmode = vga_io_rgfx(VGA_GFX_MODE);
127 vga_io_w(VGA_GFX_D, mode);
131 /* Select the Bit Mask Register and return its value. */
132 static inline int selectmask(void)
134 return vga_io_rgfx(VGA_GFX_BIT_MASK);
137 /* Set the value of the Bit Mask Register. It must already have been
138 selected with selectmask(). */
139 static inline void setmask(int mask)
141 vga_io_w(VGA_GFX_D, mask);
144 /* Set the Data Rotate Register and return its old value.
145 Bits 0-2 are rotate count, bits 3-4 are logical operation
146 (0=NOP, 1=AND, 2=OR, 3=XOR). */
147 static inline int setop(int op)
151 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
152 vga_io_w(VGA_GFX_D, op);
156 /* Set the Enable Set/Reset Register and return its old value.
157 The code here always uses value 0xf for thsi register. */
158 static inline int setsr(int sr)
162 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
163 vga_io_w(VGA_GFX_D, sr);
167 /* Set the Set/Reset Register and return its old value. */
168 static inline int setcolor(int color)
172 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
173 vga_io_w(VGA_GFX_D, color);
177 /* Return the value in the Graphics Address Register. */
178 static inline int getindex(void)
180 return vga_io_r(VGA_GFX_I);
183 /* Set the value in the Graphics Address Register. */
184 static inline void setindex(int index)
186 vga_io_w(VGA_GFX_I, index);
189 static void vga16fb_pan_var(struct fb_info *info,
190 struct fb_var_screeninfo *var)
192 struct vga16fb_par *par = info->par;
195 xoffset = var->xoffset;
196 if (info->var.bits_per_pixel == 8) {
197 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
198 } else if (par->mode & MODE_TEXT) {
199 int fh = 16; // FIXME !!! font height. Fugde for now.
200 pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
202 if (info->var.nonstd)
204 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
206 vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
207 vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
208 /* if we support CFB4, then we must! support xoffset with pixel
209 * granularity if someone supports xoffset in bit resolution */
210 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
211 vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
212 if (var->bits_per_pixel == 8)
213 vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
215 vga_io_w(VGA_ATT_IW, xoffset & 7);
216 vga_io_r(VGA_IS1_RC);
217 vga_io_w(VGA_ATT_IW, 0x20);
220 static void vga16fb_update_fix(struct fb_info *info)
222 if (info->var.bits_per_pixel == 4) {
223 if (info->var.nonstd) {
224 info->fix.type = FB_TYPE_PACKED_PIXELS;
225 info->fix.line_length = info->var.xres_virtual / 2;
227 info->fix.type = FB_TYPE_VGA_PLANES;
228 info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
229 info->fix.line_length = info->var.xres_virtual / 8;
231 } else if (info->var.bits_per_pixel == 0) {
232 info->fix.type = FB_TYPE_TEXT;
233 info->fix.type_aux = FB_AUX_TEXT_CGA;
234 info->fix.line_length = info->var.xres_virtual / 4;
236 if (info->var.nonstd) {
237 info->fix.type = FB_TYPE_VGA_PLANES;
238 info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
239 info->fix.line_length = info->var.xres_virtual / 4;
241 info->fix.type = FB_TYPE_PACKED_PIXELS;
242 info->fix.line_length = info->var.xres_virtual;
247 static void vga16fb_clock_chip(struct vga16fb_par *par,
248 unsigned int pixclock,
249 const struct fb_info *info,
252 static const struct {
256 } *ptr, *best, vgaclocks[] = {
257 { 79442 /* 12.587 */, 0x00, 0x08},
258 { 70616 /* 14.161 */, 0x04, 0x08},
259 { 39721 /* 25.175 */, 0x00, 0x00},
260 { 35308 /* 28.322 */, 0x04, 0x00},
261 { 0 /* bad */, 0x00, 0x00}};
264 pixclock = (pixclock * mul) / div;
266 err = pixclock - best->pixclock;
267 if (err < 0) err = -err;
268 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
271 tmp = pixclock - ptr->pixclock;
272 if (tmp < 0) tmp = -tmp;
278 par->misc |= best->misc;
279 par->clkdiv = best->seq_clock_mode;
280 pixclock = (best->pixclock * div) / mul;
283 #define FAIL(X) return -EINVAL
285 static int vga16fb_open(struct fb_info *info, int user)
287 struct vga16fb_par *par = info->par;
289 mutex_lock(&par->open_lock);
290 if (!par->ref_count) {
291 memset(&par->state, 0, sizeof(struct vgastate));
292 par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
294 save_vga(&par->state);
297 mutex_unlock(&par->open_lock);
302 static int vga16fb_release(struct fb_info *info, int user)
304 struct vga16fb_par *par = info->par;
306 mutex_lock(&par->open_lock);
307 if (!par->ref_count) {
308 mutex_unlock(&par->open_lock);
311 if (par->ref_count == 1)
312 restore_vga(&par->state);
314 mutex_unlock(&par->open_lock);
319 static int vga16fb_check_var(struct fb_var_screeninfo *var,
320 struct fb_info *info)
322 struct vga16fb_par *par = info->par;
323 u32 xres, right, hslen, left, xtotal;
324 u32 yres, lower, vslen, upper, ytotal;
325 u32 vxres, xoffset, vyres, yoffset;
334 if (var->bits_per_pixel == 4) {
339 mode = MODE_SKIP4 | MODE_CFB;
347 } else if (var->bits_per_pixel == 8) {
349 return -EINVAL; /* no support on EGA */
352 mode = MODE_8BPP | MODE_CFB;
355 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
361 xres = (var->xres + 7) & ~7;
362 vxres = (var->xres_virtual + 0xF) & ~0xF;
363 xoffset = (var->xoffset + 7) & ~7;
364 left = (var->left_margin + 7) & ~7;
365 right = (var->right_margin + 7) & ~7;
366 hslen = (var->hsync_len + 7) & ~7;
370 if (xres + xoffset > vxres)
371 xoffset = vxres - xres;
374 var->right_margin = right;
375 var->hsync_len = hslen;
376 var->left_margin = left;
377 var->xres_virtual = vxres;
378 var->xoffset = xoffset;
385 xtotal = xres + right + hslen + left;
387 FAIL("xtotal too big");
389 FAIL("hslen too big");
390 if (right + hslen + left > 64)
391 FAIL("hblank too big");
392 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
393 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
394 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
396 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
398 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
399 pos += left - 2; /* blank_end + 2 <= total + 5 */
400 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
402 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
405 lower = var->lower_margin;
406 vslen = var->vsync_len;
407 upper = var->upper_margin;
408 vyres = var->yres_virtual;
409 yoffset = var->yoffset;
413 if (vxres * vyres > maxmem) {
414 vyres = maxmem / vxres;
418 if (yoffset + yres > vyres)
419 yoffset = vyres - yres;
421 var->lower_margin = lower;
422 var->vsync_len = vslen;
423 var->upper_margin = upper;
424 var->yres_virtual = vyres;
425 var->yoffset = yoffset;
427 if (var->vmode & FB_VMODE_DOUBLE) {
433 ytotal = yres + lower + vslen + upper;
444 FAIL("ytotal too big");
446 FAIL("vslen too big");
447 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
448 r7 = 0x10; /* disable linecompare */
449 if (ytotal & 0x100) r7 |= 0x01;
450 if (ytotal & 0x200) r7 |= 0x20;
451 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
452 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
453 if (var->vmode & FB_VMODE_DOUBLE)
454 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
455 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
456 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
457 if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
459 pos = yoffset * vxres + (xoffset >> shift);
460 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
461 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
462 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
463 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
465 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
466 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
468 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
470 r7 |= 0x40; /* 0x40 -> DISP_END */
471 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
474 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
480 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
481 pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
482 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
483 but some SVGA chips requires all 8 bits to set */
485 FAIL("vxres too long");
486 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
487 if (mode & MODE_SKIP4)
488 par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */
490 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */
491 par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
492 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
493 par->crtc[VGA_CRTC_OVERFLOW] = r7;
495 par->vss = 0x00; /* 3DA */
497 par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
498 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
500 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
505 if (mode & MODE_8BPP)
506 /* pixel clock == vga clock / 2 */
507 vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
509 /* pixel clock == vga clock */
510 vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
512 var->red.offset = var->green.offset = var->blue.offset =
513 var->transp.offset = 0;
514 var->red.length = var->green.length = var->blue.length =
515 (par->isVGA) ? 6 : 2;
516 var->transp.length = 0;
517 var->activate = FB_ACTIVATE_NOW;
520 var->accel_flags = 0;
525 static int vga16fb_set_par(struct fb_info *info)
527 struct vga16fb_par *par = info->par;
533 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
534 if (par->mode & MODE_TEXT)
535 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
537 seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
538 seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
539 if (par->mode & MODE_TEXT)
540 seq[VGA_SEQ_MEMORY_MODE] = 0x03;
541 else if (par->mode & MODE_SKIP4)
542 seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
544 seq[VGA_SEQ_MEMORY_MODE] = 0x06;
546 gdc[VGA_GFX_SR_VALUE] = 0x00;
547 gdc[VGA_GFX_SR_ENABLE] = 0x00;
548 gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
549 gdc[VGA_GFX_DATA_ROTATE] = 0x00;
550 gdc[VGA_GFX_PLANE_READ] = 0;
551 if (par->mode & MODE_TEXT) {
552 gdc[VGA_GFX_MODE] = 0x10;
553 gdc[VGA_GFX_MISC] = 0x06;
555 if (par->mode & MODE_CFB)
556 gdc[VGA_GFX_MODE] = 0x40;
558 gdc[VGA_GFX_MODE] = 0x00;
559 gdc[VGA_GFX_MISC] = 0x05;
561 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
562 gdc[VGA_GFX_BIT_MASK] = 0xFF;
564 for (i = 0x00; i < 0x10; i++)
566 if (par->mode & MODE_TEXT)
567 atc[VGA_ATC_MODE] = 0x04;
568 else if (par->mode & MODE_8BPP)
569 atc[VGA_ATC_MODE] = 0x41;
571 atc[VGA_ATC_MODE] = 0x81;
572 atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
573 atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
574 if (par->mode & MODE_8BPP)
575 atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
577 atc[VGA_ATC_PEL] = info->var.xoffset & 7;
578 atc[VGA_ATC_COLOR_PAGE] = 0x00;
580 if (par->mode & MODE_TEXT) {
581 fh = 16; // FIXME !!! Fudge font height.
582 par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
586 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
588 /* Enable graphics register modification */
590 vga_io_w(EGA_GFX_E0, 0x00);
591 vga_io_w(EGA_GFX_E1, 0x01);
594 /* update misc output register */
595 vga_io_w(VGA_MIS_W, par->misc);
597 /* synchronous reset on */
598 vga_io_wseq(0x00, 0x01);
601 vga_io_w(VGA_PEL_MSK, par->pel_msk);
603 /* write sequencer registers */
604 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
605 for (i = 2; i < VGA_SEQ_C; i++) {
606 vga_io_wseq(i, seq[i]);
609 /* synchronous reset off */
610 vga_io_wseq(0x00, 0x03);
612 /* deprotect CRT registers 0-7 */
613 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
615 /* write CRT registers */
616 for (i = 0; i < VGA_CRTC_REGS; i++) {
617 vga_io_wcrt(i, par->crtc[i]);
620 /* write graphics controller registers */
621 for (i = 0; i < VGA_GFX_C; i++) {
622 vga_io_wgfx(i, gdc[i]);
625 /* write attribute controller registers */
626 for (i = 0; i < VGA_ATT_C; i++) {
627 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
628 vga_io_wattr(i, atc[i]);
631 /* Wait for screen to stabilize. */
634 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
636 vga_io_r(VGA_IS1_RC);
637 vga_io_w(VGA_ATT_IW, 0x20);
639 vga16fb_update_fix(info);
643 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
645 static const unsigned char map[] = { 000, 001, 010, 011 };
650 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
651 vga_io_r(VGA_IS1_RC); /* ! 0x3BA */
652 vga_io_wattr(regno, val);
653 vga_io_r(VGA_IS1_RC); /* some clones need it */
654 vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
657 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
659 outb(regno, VGA_PEL_IW);
660 outb(red >> 10, VGA_PEL_D);
661 outb(green >> 10, VGA_PEL_D);
662 outb(blue >> 10, VGA_PEL_D);
665 static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
666 unsigned blue, unsigned transp,
667 struct fb_info *info)
669 struct vga16fb_par *par = info->par;
673 * Set a single color register. The values supplied are
674 * already rounded down to the hardware's capabilities
675 * (according to the entries in the `var' structure). Return
676 * != 0 for invalid regno.
682 gray = info->var.grayscale;
685 /* gray = 0.30*R + 0.59*G + 0.11*B */
686 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
689 vga16_setpalette(regno,red,green,blue);
691 ega16_setpalette(regno,red,green,blue);
695 static int vga16fb_pan_display(struct fb_var_screeninfo *var,
696 struct fb_info *info)
698 vga16fb_pan_var(info, var);
702 /* The following VESA blanking code is taken from vgacon.c. The VGA
703 blanking code was originally by Huang shi chao, and modified by
704 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
705 (tjd@barefoot.org) for Linux. */
707 static void vga_vesa_blank(struct vga16fb_par *par, int mode)
709 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
710 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
712 /* save original values of VGA controller registers */
713 if(!par->vesa_blanked) {
714 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
717 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
718 par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */
719 par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */
720 par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */
721 par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */
722 par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */
723 par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */
724 par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
725 par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */
728 /* assure that video is enabled */
729 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
730 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
732 /* test for vertical retrace in process.... */
733 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
734 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
737 * Set <End of vertical retrace> to minimum (0) and
738 * <Start of vertical Retrace> to maximum (incl. overflow)
739 * Result: turn off vertical sync (VSync) pulse.
741 if (mode & FB_BLANK_VSYNC_SUSPEND) {
742 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
743 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
744 /* bits 9,10 of vert. retrace */
745 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
748 if (mode & FB_BLANK_HSYNC_SUSPEND) {
750 * Set <End of horizontal retrace> to minimum (0) and
751 * <Start of horizontal Retrace> to maximum
752 * Result: turn off horizontal sync (HSync) pulse.
754 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
755 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
758 /* restore both index registers */
759 outb_p(SeqCtrlIndex, VGA_SEQ_I);
760 outb_p(CrtCtrlIndex, VGA_CRT_IC);
763 static void vga_vesa_unblank(struct vga16fb_par *par)
765 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
766 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
768 /* restore original values of VGA controller registers */
769 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
771 /* HorizontalTotal */
772 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
773 /* HorizDisplayEnd */
774 vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
775 /* StartHorizRetrace */
776 vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
777 /* EndHorizRetrace */
778 vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
780 vga_io_wcrt(0x07, par->vga_state.Overflow);
781 /* StartVertRetrace */
782 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
784 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
786 vga_io_wcrt(0x17, par->vga_state.ModeControl);
788 vga_io_wseq(0x01, par->vga_state.ClockingMode);
790 /* restore index/control registers */
791 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
792 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
795 static void vga_pal_blank(void)
799 for (i=0; i<16; i++) {
800 outb_p(i, VGA_PEL_IW);
801 outb_p(0, VGA_PEL_D);
802 outb_p(0, VGA_PEL_D);
803 outb_p(0, VGA_PEL_D);
807 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
808 static int vga16fb_blank(int blank, struct fb_info *info)
810 struct vga16fb_par *par = info->par;
813 case FB_BLANK_UNBLANK: /* Unblank */
814 if (par->vesa_blanked) {
815 vga_vesa_unblank(par);
816 par->vesa_blanked = 0;
818 if (par->palette_blanked) {
819 par->palette_blanked = 0;
822 case FB_BLANK_NORMAL: /* blank */
824 par->palette_blanked = 1;
826 default: /* VESA blanking */
827 vga_vesa_blank(par, blank);
828 par->vesa_blanked = 1;
834 static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
836 u32 dx = rect->dx, width = rect->width;
837 char oldindex = getindex();
838 char oldmode = setmode(0x40);
839 char oldmask = selectmask();
840 int line_ofs, height;
845 where = info->screen_base + dx + rect->dy * info->fix.line_length;
847 if (rect->rop == ROP_COPY) {
852 line_ofs = info->fix.line_length - width;
855 height = rect->height;
860 /* we can do memset... */
861 for (x = width; x > 0; --x) {
862 writeb(rect->color, where);
868 char oldcolor = setcolor(0xf);
874 for (y = 0; y < rect->height; y++) {
877 where += info->fix.line_length;
888 static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
890 int x, x2, y2, vxres, vyres, width, height, line_ofs;
893 vxres = info->var.xres_virtual;
894 vyres = info->var.yres_virtual;
896 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
899 /* We could use hardware clipping but on many cards you get around
900 * hardware clipping by writing to framebuffer directly. */
902 x2 = rect->dx + rect->width;
903 y2 = rect->dy + rect->height;
904 x2 = x2 < vxres ? x2 : vxres;
905 y2 = y2 < vyres ? y2 : vyres;
906 width = x2 - rect->dx;
908 switch (info->fix.type) {
909 case FB_TYPE_VGA_PLANES:
910 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
912 height = y2 - rect->dy;
913 width = rect->width/8;
915 line_ofs = info->fix.line_length - width;
916 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
923 setcolor(rect->color);
929 for (x = 0; x < width; x++) {
945 for (x = 0; x < width; x++) {
954 vga_8planes_fillrect(info, rect);
956 case FB_TYPE_PACKED_PIXELS:
958 cfb_fillrect(info, rect);
963 static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
965 char oldindex = getindex();
966 char oldmode = setmode(0x41);
967 char oldop = setop(0);
968 char oldsr = setsr(0xf);
969 int height, line_ofs, x;
974 height = area->height;
978 width = area->width / 4;
980 if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
981 line_ofs = info->fix.line_length - width;
982 dest = info->screen_base + dx + area->dy * info->fix.line_length;
983 src = info->screen_base + sx + area->sy * info->fix.line_length;
985 for (x = 0; x < width; x++) {
995 line_ofs = info->fix.line_length - width;
996 dest = info->screen_base + dx + width +
997 (area->dy + height - 1) * info->fix.line_length;
998 src = info->screen_base + sx + width +
999 (area->sy + height - 1) * info->fix.line_length;
1001 for (x = 0; x < width; x++) {
1018 static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1020 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1021 int x, x2, y2, old_dx, old_dy, vxres, vyres;
1022 int height, width, line_ofs;
1023 char __iomem *dst = NULL;
1024 char __iomem *src = NULL;
1026 vxres = info->var.xres_virtual;
1027 vyres = info->var.yres_virtual;
1029 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1033 /* clip the destination */
1038 * We could use hardware clipping but on many cards you get around
1039 * hardware clipping by writing to framebuffer directly.
1041 x2 = area->dx + area->width;
1042 y2 = area->dy + area->height;
1043 dx = area->dx > 0 ? area->dx : 0;
1044 dy = area->dy > 0 ? area->dy : 0;
1045 x2 = x2 < vxres ? x2 : vxres;
1046 y2 = y2 < vyres ? y2 : vyres;
1050 if (sx + dx < old_dx || sy + dy < old_dy)
1053 /* update sx1,sy1 */
1054 sx += (dx - old_dx);
1055 sy += (dy - old_dy);
1057 /* the source must be completely inside the virtual screen */
1058 if (sx + width > vxres || sy + height > vyres)
1061 switch (info->fix.type) {
1062 case FB_TYPE_VGA_PLANES:
1063 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1066 line_ofs = info->fix.line_length - width;
1072 if (dy < sy || (dy == sy && dx < sx)) {
1073 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1074 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1076 for (x = 0; x < width; x++) {
1086 dst = info->screen_base + (dx/8) + width +
1087 (dy + height - 1) * info->fix.line_length;
1088 src = info->screen_base + (sx/8) + width +
1089 (sy + height - 1) * info->fix.line_length;
1091 for (x = 0; x < width; x++) {
1102 vga_8planes_copyarea(info, area);
1104 case FB_TYPE_PACKED_PIXELS:
1106 cfb_copyarea(info, area);
1111 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1112 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1113 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1115 #if defined(__LITTLE_ENDIAN)
1116 static const u16 transl_l[] = TRANS_MASK_LOW;
1117 static const u16 transl_h[] = TRANS_MASK_HIGH;
1118 #elif defined(__BIG_ENDIAN)
1119 static const u16 transl_l[] = TRANS_MASK_HIGH;
1120 static const u16 transl_h[] = TRANS_MASK_LOW;
1122 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1125 static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1127 char oldindex = getindex();
1128 char oldmode = setmode(0x40);
1129 char oldop = setop(0);
1130 char oldsr = setsr(0);
1131 char oldmask = selectmask();
1132 const char *cdat = image->data;
1134 char __iomem *where;
1138 where = info->screen_base + dx + image->dy * info->fix.line_length;
1141 writeb(image->bg_color, where);
1144 setmask(image->fg_color ^ image->bg_color);
1147 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1148 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1156 static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1158 char __iomem *where = info->screen_base + (image->dx/8) +
1159 image->dy * info->fix.line_length;
1160 struct vga16fb_par *par = info->par;
1161 char *cdat = (char *) image->data;
1165 switch (info->fix.type) {
1166 case FB_TYPE_VGA_PLANES:
1167 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1172 setcolor(image->fg_color);
1176 writeb(image->bg_color, where);
1178 readb(where); /* fill latches */
1181 for (y = 0; y < image->height; y++) {
1183 for (x = image->width/8; x--;)
1184 writeb(*cdat++, dst++);
1185 where += info->fix.line_length;
1192 setcolor(image->bg_color);
1196 for (y = 0; y < image->height; y++) {
1198 for (x=image->width/8; x--;){
1200 setcolor(image->fg_color);
1207 where += info->fix.line_length;
1211 vga_8planes_imageblit(info, image);
1213 case FB_TYPE_PACKED_PIXELS:
1215 cfb_imageblit(info, image);
1220 static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1225 struct vga16fb_par *par = info->par;
1226 char __iomem *where =
1227 info->screen_base + image->dy * info->fix.line_length +
1229 const char *cdat = image->data;
1233 switch (info->fix.type) {
1234 case FB_TYPE_VGA_PLANES:
1235 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1241 for (y = 0; y < image->height; y++) {
1242 for (x = 0; x < image->width; x++) {
1247 setmask(1 << (7 - (x % 8)));
1253 where += info->fix.line_length;
1257 case FB_TYPE_PACKED_PIXELS:
1258 cfb_imageblit(info, image);
1265 static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1267 if (image->depth == 1)
1268 vga_imageblit_expand(info, image);
1270 vga_imageblit_color(info, image);
1273 static struct fb_ops vga16fb_ops = {
1274 .owner = THIS_MODULE,
1275 .fb_open = vga16fb_open,
1276 .fb_release = vga16fb_release,
1277 .fb_check_var = vga16fb_check_var,
1278 .fb_set_par = vga16fb_set_par,
1279 .fb_setcolreg = vga16fb_setcolreg,
1280 .fb_pan_display = vga16fb_pan_display,
1281 .fb_blank = vga16fb_blank,
1282 .fb_fillrect = vga16fb_fillrect,
1283 .fb_copyarea = vga16fb_copyarea,
1284 .fb_imageblit = vga16fb_imageblit,
1288 static int vga16fb_setup(char *options)
1292 if (!options || !*options)
1295 while ((this_opt = strsep(&options, ",")) != NULL) {
1296 if (!*this_opt) continue;
1302 static int __init vga16fb_probe(struct platform_device *dev)
1304 struct fb_info *info;
1305 struct vga16fb_par *par;
1309 printk(KERN_DEBUG "vga16fb: initializing\n");
1310 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1317 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1318 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1320 if (!info->screen_base) {
1321 printk(KERN_ERR "vga16fb: unable to map device\n");
1326 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1329 mutex_init(&par->open_lock);
1330 par->isVGA = screen_info.orig_video_isVGA;
1331 par->palette_blanked = 0;
1332 par->vesa_blanked = 0;
1334 i = par->isVGA? 6 : 2;
1336 vga16fb_defined.red.length = i;
1337 vga16fb_defined.green.length = i;
1338 vga16fb_defined.blue.length = i;
1340 /* name should not depend on EGA/VGA */
1341 info->fbops = &vga16fb_ops;
1342 info->var = vga16fb_defined;
1343 info->fix = vga16fb_fix;
1344 /* supports rectangles with widths of multiples of 8 */
1345 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1346 info->flags = FBINFO_FLAG_DEFAULT |
1347 FBINFO_HWACCEL_YPAN;
1349 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1350 ret = fb_alloc_cmap(&info->cmap, i, 0);
1352 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1354 goto err_alloc_cmap;
1357 if (vga16fb_check_var(&info->var, info)) {
1358 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1363 vga16fb_update_fix(info);
1365 if (register_framebuffer(info) < 0) {
1366 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1371 printk(KERN_INFO "fb%d: %s frame buffer device\n",
1372 info->node, info->fix.id);
1373 platform_set_drvdata(dev, info);
1378 fb_dealloc_cmap(&info->cmap);
1380 iounmap(info->screen_base);
1382 framebuffer_release(info);
1387 static int vga16fb_remove(struct platform_device *dev)
1389 struct fb_info *info = platform_get_drvdata(dev);
1392 unregister_framebuffer(info);
1393 iounmap(info->screen_base);
1394 fb_dealloc_cmap(&info->cmap);
1395 /* XXX unshare VGA regions */
1396 framebuffer_release(info);
1402 static struct platform_driver vga16fb_driver = {
1403 .probe = vga16fb_probe,
1404 .remove = vga16fb_remove,
1410 static struct platform_device *vga16fb_device;
1412 static int __init vga16fb_init(void)
1416 char *option = NULL;
1418 if (fb_get_options("vga16fb", &option))
1421 vga16fb_setup(option);
1423 ret = platform_driver_register(&vga16fb_driver);
1426 vga16fb_device = platform_device_alloc("vga16fb", 0);
1429 ret = platform_device_add(vga16fb_device);
1434 platform_device_put(vga16fb_device);
1435 platform_driver_unregister(&vga16fb_driver);
1442 static void __exit vga16fb_exit(void)
1444 platform_device_unregister(vga16fb_device);
1445 platform_driver_unregister(&vga16fb_driver);
1448 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1449 MODULE_LICENSE("GPL");
1450 module_init(vga16fb_init);
1451 module_exit(vga16fb_exit);
1455 * Overrides for Emacs so that we follow Linus's tabbing style.
1456 * ---------------------------------------------------------------------------