Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
0003  * 
0004  * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
0005  * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
0006  * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
0007  *
0008  * This file is subject to the terms and conditions of the GNU General
0009  * Public License.  See the file COPYING in the main directory of this
0010  * archive for more details.  
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/kernel.h>
0015 #include <linux/errno.h>
0016 #include <linux/string.h>
0017 #include <linux/mm.h>
0018 #include <linux/delay.h>
0019 #include <linux/fb.h>
0020 #include <linux/ioport.h>
0021 #include <linux/init.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/screen_info.h>
0024 
0025 #include <asm/io.h>
0026 #include <video/vga.h>
0027 
0028 #define VGA_FB_PHYS 0xA0000
0029 #define VGA_FB_PHYS_LEN 65536
0030 
0031 #define MODE_SKIP4  1
0032 #define MODE_8BPP   2
0033 #define MODE_CFB    4
0034 #define MODE_TEXT   8
0035 
0036 /* --------------------------------------------------------------------- */
0037 
0038 /*
0039  * card parameters
0040  */
0041 
0042 struct vga16fb_par {
0043     /* structure holding original VGA register settings when the
0044            screen is blanked */
0045     struct {
0046         unsigned char   SeqCtrlIndex;     /* Sequencer Index reg.   */
0047         unsigned char   CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
0048         unsigned char   CrtMiscIO;    /* Miscellaneous register */
0049         unsigned char   HorizontalTotal;  /* CRT-Controller:00h */
0050         unsigned char   HorizDisplayEnd;  /* CRT-Controller:01h */
0051         unsigned char   StartHorizRetrace;/* CRT-Controller:04h */
0052         unsigned char   EndHorizRetrace;  /* CRT-Controller:05h */
0053         unsigned char   Overflow;     /* CRT-Controller:07h */
0054         unsigned char   StartVertRetrace; /* CRT-Controller:10h */
0055         unsigned char   EndVertRetrace;   /* CRT-Controller:11h */
0056         unsigned char   ModeControl;      /* CRT-Controller:17h */
0057         unsigned char   ClockingMode;     /* Seq-Controller:01h */
0058     } vga_state;
0059     struct vgastate state;
0060     unsigned int ref_count;
0061     int palette_blanked, vesa_blanked, mode, isVGA;
0062     u8 misc, pel_msk, vss, clkdiv;
0063     u8 crtc[VGA_CRT_C];
0064 };
0065 
0066 /* --------------------------------------------------------------------- */
0067 
0068 static struct fb_var_screeninfo vga16fb_defined = {
0069     .xres       = 640,
0070     .yres       = 480,
0071     .xres_virtual   = 640,
0072     .yres_virtual   = 480,
0073     .bits_per_pixel = 4,    
0074     .activate   = FB_ACTIVATE_TEST,
0075     .height     = -1,
0076     .width      = -1,
0077     .pixclock   = 39721,
0078     .left_margin    = 48,
0079     .right_margin   = 16,
0080     .upper_margin   = 33,
0081     .lower_margin   = 10,
0082     .hsync_len  = 96,
0083     .vsync_len  = 2,
0084     .vmode      = FB_VMODE_NONINTERLACED,
0085 };
0086 
0087 /* name should not depend on EGA/VGA */
0088 static const struct fb_fix_screeninfo vga16fb_fix = {
0089     .id     = "VGA16 VGA",
0090     .smem_start = VGA_FB_PHYS,
0091     .smem_len   = VGA_FB_PHYS_LEN,
0092     .type       = FB_TYPE_VGA_PLANES,
0093     .type_aux   = FB_AUX_VGA_PLANES_VGA4,
0094     .visual     = FB_VISUAL_PSEUDOCOLOR,
0095     .xpanstep   = 8,
0096     .ypanstep   = 1,
0097     .line_length    = 640 / 8,
0098     .accel      = FB_ACCEL_NONE
0099 };
0100 
0101 /* The VGA's weird architecture often requires that we read a byte and
0102    write a byte to the same location.  It doesn't matter *what* byte
0103    we write, however.  This is because all the action goes on behind
0104    the scenes in the VGA's 32-bit latch register, and reading and writing
0105    video memory just invokes latch behavior.
0106 
0107    To avoid race conditions (is this necessary?), reading and writing
0108    the memory byte should be done with a single instruction.  One
0109    suitable instruction is the x86 bitwise OR.  The following
0110    read-modify-write routine should optimize to one such bitwise
0111    OR. */
0112 static inline void rmw(volatile char __iomem *p)
0113 {
0114     readb(p);
0115     writeb(1, p);
0116 }
0117 
0118 /* Set the Graphics Mode Register, and return its previous value.
0119    Bits 0-1 are write mode, bit 3 is read mode. */
0120 static inline int setmode(int mode)
0121 {
0122     int oldmode;
0123     
0124     oldmode = vga_io_rgfx(VGA_GFX_MODE);
0125     vga_io_w(VGA_GFX_D, mode);
0126     return oldmode;
0127 }
0128 
0129 /* Select the Bit Mask Register and return its value. */
0130 static inline int selectmask(void)
0131 {
0132     return vga_io_rgfx(VGA_GFX_BIT_MASK);
0133 }
0134 
0135 /* Set the value of the Bit Mask Register.  It must already have been
0136    selected with selectmask(). */
0137 static inline void setmask(int mask)
0138 {
0139     vga_io_w(VGA_GFX_D, mask);
0140 }
0141 
0142 /* Set the Data Rotate Register and return its old value. 
0143    Bits 0-2 are rotate count, bits 3-4 are logical operation
0144    (0=NOP, 1=AND, 2=OR, 3=XOR). */
0145 static inline int setop(int op)
0146 {
0147     int oldop;
0148     
0149     oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
0150     vga_io_w(VGA_GFX_D, op);
0151     return oldop;
0152 }
0153 
0154 /* Set the Enable Set/Reset Register and return its old value.  
0155    The code here always uses value 0xf for this register. */
0156 static inline int setsr(int sr)
0157 {
0158     int oldsr;
0159 
0160     oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
0161     vga_io_w(VGA_GFX_D, sr);
0162     return oldsr;
0163 }
0164 
0165 /* Set the Set/Reset Register and return its old value. */
0166 static inline int setcolor(int color)
0167 {
0168     int oldcolor;
0169 
0170     oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
0171     vga_io_w(VGA_GFX_D, color);
0172     return oldcolor;
0173 }
0174 
0175 /* Return the value in the Graphics Address Register. */
0176 static inline int getindex(void)
0177 {
0178     return vga_io_r(VGA_GFX_I);
0179 }
0180 
0181 /* Set the value in the Graphics Address Register. */
0182 static inline void setindex(int index)
0183 {
0184     vga_io_w(VGA_GFX_I, index);
0185 }
0186 
0187 /* Check if the video mode is supported by the driver */
0188 static inline int check_mode_supported(void)
0189 {
0190     /* non-x86 architectures treat orig_video_isVGA as a boolean flag */
0191 #if defined(CONFIG_X86)
0192     /* only EGA and VGA in 16 color graphic mode are supported */
0193     if (screen_info.orig_video_isVGA != VIDEO_TYPE_EGAC &&
0194         screen_info.orig_video_isVGA != VIDEO_TYPE_VGAC)
0195         return -ENODEV;
0196 
0197     if (screen_info.orig_video_mode != 0x0D &&  /* 320x200/4 (EGA) */
0198         screen_info.orig_video_mode != 0x0E &&  /* 640x200/4 (EGA) */
0199         screen_info.orig_video_mode != 0x10 &&  /* 640x350/4 (EGA) */
0200         screen_info.orig_video_mode != 0x12)    /* 640x480/4 (VGA) */
0201         return -ENODEV;
0202 #endif
0203     return 0;
0204 }
0205 
0206 static void vga16fb_pan_var(struct fb_info *info, 
0207                 struct fb_var_screeninfo *var)
0208 {
0209     struct vga16fb_par *par = info->par;
0210     u32 xoffset, pos;
0211 
0212     xoffset = var->xoffset;
0213     if (info->var.bits_per_pixel == 8) {
0214         pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
0215     } else if (par->mode & MODE_TEXT) {
0216         int fh = 16; // FIXME !!! font height. Fugde for now.
0217         pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
0218     } else {
0219         if (info->var.nonstd)
0220             xoffset--;
0221         pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
0222     }
0223     vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
0224     vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
0225     /* if we support CFB4, then we must! support xoffset with pixel
0226      * granularity if someone supports xoffset in bit resolution */
0227     vga_io_r(VGA_IS1_RC);       /* reset flip-flop */
0228     vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
0229     if (info->var.bits_per_pixel == 8)
0230         vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
0231     else
0232         vga_io_w(VGA_ATT_IW, xoffset & 7);
0233     vga_io_r(VGA_IS1_RC);
0234     vga_io_w(VGA_ATT_IW, 0x20);
0235 }
0236 
0237 static void vga16fb_update_fix(struct fb_info *info)
0238 {
0239     if (info->var.bits_per_pixel == 4) {
0240         if (info->var.nonstd) {
0241             info->fix.type = FB_TYPE_PACKED_PIXELS;
0242             info->fix.line_length = info->var.xres_virtual / 2;
0243         } else {
0244             info->fix.type = FB_TYPE_VGA_PLANES;
0245             info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
0246             info->fix.line_length = info->var.xres_virtual / 8;
0247         }
0248     } else if (info->var.bits_per_pixel == 0) {
0249         info->fix.type = FB_TYPE_TEXT;
0250         info->fix.type_aux = FB_AUX_TEXT_CGA;
0251         info->fix.line_length = info->var.xres_virtual / 4;
0252     } else {    /* 8bpp */
0253         if (info->var.nonstd) {
0254             info->fix.type = FB_TYPE_VGA_PLANES;
0255             info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
0256             info->fix.line_length = info->var.xres_virtual / 4;
0257         } else {
0258             info->fix.type = FB_TYPE_PACKED_PIXELS;
0259             info->fix.line_length = info->var.xres_virtual;
0260         }
0261     }
0262 }
0263 
0264 static void vga16fb_clock_chip(struct vga16fb_par *par,
0265                    unsigned int *pixclock,
0266                    const struct fb_info *info,
0267                    int mul, int div)
0268 {
0269     static const struct {
0270         u32 pixclock;
0271         u8  misc;
0272         u8  seq_clock_mode;
0273     } *ptr, *best, vgaclocks[] = {
0274         { 79442 /* 12.587 */, 0x00, 0x08},
0275         { 70616 /* 14.161 */, 0x04, 0x08},
0276         { 39721 /* 25.175 */, 0x00, 0x00},
0277         { 35308 /* 28.322 */, 0x04, 0x00},
0278         {     0 /* bad */,    0x00, 0x00}};
0279     int err;
0280 
0281     *pixclock = (*pixclock * mul) / div;
0282     best = vgaclocks;
0283     err = *pixclock - best->pixclock;
0284     if (err < 0) err = -err;
0285     for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
0286         int tmp;
0287 
0288         tmp = *pixclock - ptr->pixclock;
0289         if (tmp < 0) tmp = -tmp;
0290         if (tmp < err) {
0291             err = tmp;
0292             best = ptr;
0293         }
0294     }
0295     par->misc |= best->misc;
0296     par->clkdiv = best->seq_clock_mode;
0297     *pixclock = (best->pixclock * div) / mul;
0298 }
0299                    
0300 #define FAIL(X) return -EINVAL
0301 
0302 static int vga16fb_open(struct fb_info *info, int user)
0303 {
0304     struct vga16fb_par *par = info->par;
0305 
0306     if (!par->ref_count) {
0307         memset(&par->state, 0, sizeof(struct vgastate));
0308         par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
0309             VGA_SAVE_CMAP;
0310         save_vga(&par->state);
0311     }
0312     par->ref_count++;
0313 
0314     return 0;
0315 }
0316 
0317 static int vga16fb_release(struct fb_info *info, int user)
0318 {
0319     struct vga16fb_par *par = info->par;
0320 
0321     if (!par->ref_count)
0322         return -EINVAL;
0323 
0324     if (par->ref_count == 1)
0325         restore_vga(&par->state);
0326     par->ref_count--;
0327 
0328     return 0;
0329 }
0330 
0331 static int vga16fb_check_var(struct fb_var_screeninfo *var,
0332                  struct fb_info *info)
0333 {
0334     struct vga16fb_par *par = info->par;
0335     u32 xres, right, hslen, left, xtotal;
0336     u32 yres, lower, vslen, upper, ytotal;
0337     u32 vxres, xoffset, vyres, yoffset;
0338     u32 pos;
0339     u8 r7, rMode;
0340     int shift;
0341     int mode;
0342     u32 maxmem;
0343 
0344     par->pel_msk = 0xFF;
0345 
0346     if (var->bits_per_pixel == 4) {
0347         if (var->nonstd) {
0348             if (!par->isVGA)
0349                 return -EINVAL;
0350             shift = 3;
0351             mode = MODE_SKIP4 | MODE_CFB;
0352             maxmem = 16384;
0353             par->pel_msk = 0x0F;
0354         } else {
0355             shift = 3;
0356             mode = 0;
0357             maxmem = 65536;
0358         }
0359     } else if (var->bits_per_pixel == 8) {
0360         if (!par->isVGA)
0361             return -EINVAL; /* no support on EGA */
0362         shift = 2;
0363         if (var->nonstd) {
0364             mode = MODE_8BPP | MODE_CFB;
0365             maxmem = 65536;
0366         } else {
0367             mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
0368             maxmem = 16384;
0369         }
0370     } else
0371         return -EINVAL;
0372 
0373     xres = (var->xres + 7) & ~7;
0374     vxres = (var->xres_virtual + 0xF) & ~0xF;
0375     xoffset = (var->xoffset + 7) & ~7;
0376     left = (var->left_margin + 7) & ~7;
0377     right = (var->right_margin + 7) & ~7;
0378     hslen = (var->hsync_len + 7) & ~7;
0379 
0380     if (vxres < xres)
0381         vxres = xres;
0382     if (xres + xoffset > vxres)
0383         xoffset = vxres - xres;
0384 
0385     var->xres = xres;
0386     var->right_margin = right;
0387     var->hsync_len = hslen;
0388     var->left_margin = left;
0389     var->xres_virtual = vxres;
0390     var->xoffset = xoffset;
0391 
0392     xres >>= shift;
0393     right >>= shift;
0394     hslen >>= shift;
0395     left >>= shift;
0396     vxres >>= shift;
0397     xtotal = xres + right + hslen + left;
0398     if (xtotal >= 256)
0399         FAIL("xtotal too big");
0400     if (hslen > 32)
0401         FAIL("hslen too big");
0402     if (right + hslen + left > 64)
0403         FAIL("hblank too big");
0404     par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
0405     par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
0406     par->crtc[VGA_CRTC_H_DISP] = xres - 1;
0407     pos = xres + right;
0408     par->crtc[VGA_CRTC_H_SYNC_START] = pos;
0409     pos += hslen;
0410     par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
0411     pos += left - 2; /* blank_end + 2 <= total + 5 */
0412     par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
0413     if (pos & 0x20)
0414         par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
0415 
0416     yres = var->yres;
0417     lower = var->lower_margin;
0418     vslen = var->vsync_len;
0419     upper = var->upper_margin;
0420     vyres = var->yres_virtual;
0421     yoffset = var->yoffset;
0422 
0423     if (yres > vyres)
0424         vyres = yres;
0425     if (vxres * vyres > maxmem) {
0426         vyres = maxmem / vxres;
0427         if (vyres < yres)
0428             return -ENOMEM;
0429     }
0430     if (yoffset + yres > vyres)
0431         yoffset = vyres - yres;
0432     var->yres = yres;
0433     var->lower_margin = lower;
0434     var->vsync_len = vslen;
0435     var->upper_margin = upper;
0436     var->yres_virtual = vyres;
0437     var->yoffset = yoffset;
0438 
0439     if (var->vmode & FB_VMODE_DOUBLE) {
0440         yres <<= 1;
0441         lower <<= 1;
0442         vslen <<= 1;
0443         upper <<= 1;
0444     }
0445     ytotal = yres + lower + vslen + upper;
0446     if (ytotal > 1024) {
0447         ytotal >>= 1;
0448         yres >>= 1;
0449         lower >>= 1;
0450         vslen >>= 1;
0451         upper >>= 1;
0452         rMode = 0x04;
0453     } else
0454         rMode = 0x00;
0455     if (ytotal > 1024)
0456         FAIL("ytotal too big");
0457     if (vslen > 16)
0458         FAIL("vslen too big");
0459     par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
0460     r7 = 0x10;  /* disable linecompare */
0461     if (ytotal & 0x100) r7 |= 0x01;
0462     if (ytotal & 0x200) r7 |= 0x20;
0463     par->crtc[VGA_CRTC_PRESET_ROW] = 0;
0464     par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;    /* 1 scanline, no linecmp */
0465     if (var->vmode & FB_VMODE_DOUBLE)
0466         par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
0467     par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
0468     par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
0469     if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
0470         xoffset--;
0471     pos = yoffset * vxres + (xoffset >> shift);
0472     par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
0473     par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
0474     par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
0475     par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
0476     pos = yres - 1;
0477     par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
0478     par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
0479     if (pos & 0x100)
0480         r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
0481     if (pos & 0x200) {
0482         r7 |= 0x40; /* 0x40 -> DISP_END */
0483         par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
0484     }
0485     pos += lower;
0486     par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
0487     if (pos & 0x100)
0488         r7 |= 0x04;
0489     if (pos & 0x200)
0490         r7 |= 0x80;
0491     pos += vslen;
0492     par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
0493     pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
0494     par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
0495                      but some SVGA chips requires all 8 bits to set */
0496     if (vxres >= 512)
0497         FAIL("vxres too long");
0498     par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
0499     if (mode & MODE_SKIP4)
0500         par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;   /* 256, cfb8 */
0501     else
0502         par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;   /* 16, vgap */
0503     par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
0504     par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
0505     par->crtc[VGA_CRTC_OVERFLOW] = r7;
0506 
0507     par->vss = 0x00;    /* 3DA */
0508 
0509     par->misc = 0xE3;   /* enable CPU, ports 0x3Dx, positive sync */
0510     if (var->sync & FB_SYNC_HOR_HIGH_ACT)
0511         par->misc &= ~0x40;
0512     if (var->sync & FB_SYNC_VERT_HIGH_ACT)
0513         par->misc &= ~0x80;
0514     
0515     par->mode = mode;
0516 
0517     if (mode & MODE_8BPP)
0518         /* pixel clock == vga clock / 2 */
0519         vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
0520     else
0521         /* pixel clock == vga clock */
0522         vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
0523     
0524     var->red.offset = var->green.offset = var->blue.offset = 
0525     var->transp.offset = 0;
0526     var->red.length = var->green.length = var->blue.length =
0527         (par->isVGA) ? 6 : 2;
0528     var->transp.length = 0;
0529     var->activate = FB_ACTIVATE_NOW;
0530     var->height = -1;
0531     var->width = -1;
0532     var->accel_flags = 0;
0533     return 0;
0534 }
0535 #undef FAIL
0536 
0537 static int vga16fb_set_par(struct fb_info *info)
0538 {
0539     struct vga16fb_par *par = info->par;
0540     u8 gdc[VGA_GFX_C];
0541     u8 seq[VGA_SEQ_C];
0542     u8 atc[VGA_ATT_C];
0543     int fh, i;
0544 
0545     seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
0546     if (par->mode & MODE_TEXT)
0547         seq[VGA_SEQ_PLANE_WRITE] = 0x03;
0548     else
0549         seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
0550     seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
0551     if (par->mode & MODE_TEXT)
0552         seq[VGA_SEQ_MEMORY_MODE] = 0x03;
0553     else if (par->mode & MODE_SKIP4)
0554         seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
0555     else
0556         seq[VGA_SEQ_MEMORY_MODE] = 0x06;
0557 
0558     gdc[VGA_GFX_SR_VALUE] = 0x00;
0559     gdc[VGA_GFX_SR_ENABLE] = 0x00;
0560     gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
0561     gdc[VGA_GFX_DATA_ROTATE] = 0x00;
0562     gdc[VGA_GFX_PLANE_READ] = 0;
0563     if (par->mode & MODE_TEXT) {
0564         gdc[VGA_GFX_MODE] = 0x10;
0565         gdc[VGA_GFX_MISC] = 0x06;
0566     } else {
0567         if (par->mode & MODE_CFB)
0568             gdc[VGA_GFX_MODE] = 0x40;
0569         else
0570             gdc[VGA_GFX_MODE] = 0x00;
0571         gdc[VGA_GFX_MISC] = 0x05;
0572     }
0573     gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
0574     gdc[VGA_GFX_BIT_MASK] = 0xFF;
0575 
0576     for (i = 0x00; i < 0x10; i++)
0577         atc[i] = i;
0578     if (par->mode & MODE_TEXT)
0579         atc[VGA_ATC_MODE] = 0x04;
0580     else if (par->mode & MODE_8BPP)
0581         atc[VGA_ATC_MODE] = 0x41;
0582     else
0583         atc[VGA_ATC_MODE] = 0x81;
0584     atc[VGA_ATC_OVERSCAN] = 0x00;   /* 0 for EGA, 0xFF for VGA */
0585     atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
0586     if (par->mode & MODE_8BPP)
0587         atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
0588     else
0589         atc[VGA_ATC_PEL] = info->var.xoffset & 7;
0590     atc[VGA_ATC_COLOR_PAGE] = 0x00;
0591     
0592     if (par->mode & MODE_TEXT) {
0593         fh = 16; // FIXME !!! Fudge font height. 
0594         par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] 
0595                            & ~0x1F) | (fh - 1);
0596     }
0597 
0598     vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
0599 
0600     /* Enable graphics register modification */
0601     if (!par->isVGA) {
0602         vga_io_w(EGA_GFX_E0, 0x00);
0603         vga_io_w(EGA_GFX_E1, 0x01);
0604     }
0605     
0606     /* update misc output register */
0607     vga_io_w(VGA_MIS_W, par->misc);
0608     
0609     /* synchronous reset on */
0610     vga_io_wseq(0x00, 0x01);
0611 
0612     if (par->isVGA)
0613         vga_io_w(VGA_PEL_MSK, par->pel_msk);
0614 
0615     /* write sequencer registers */
0616     vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
0617     for (i = 2; i < VGA_SEQ_C; i++) {
0618         vga_io_wseq(i, seq[i]);
0619     }
0620     
0621     /* synchronous reset off */
0622     vga_io_wseq(0x00, 0x03);
0623 
0624     /* deprotect CRT registers 0-7 */
0625     vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
0626 
0627     /* write CRT registers */
0628     for (i = 0; i < VGA_CRTC_REGS; i++) {
0629         vga_io_wcrt(i, par->crtc[i]);
0630     }
0631     
0632     /* write graphics controller registers */
0633     for (i = 0; i < VGA_GFX_C; i++) {
0634         vga_io_wgfx(i, gdc[i]);
0635     }
0636     
0637     /* write attribute controller registers */
0638     for (i = 0; i < VGA_ATT_C; i++) {
0639         vga_io_r(VGA_IS1_RC);       /* reset flip-flop */
0640         vga_io_wattr(i, atc[i]);
0641     }
0642 
0643     /* Wait for screen to stabilize. */
0644     mdelay(50);
0645 
0646     vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
0647 
0648     vga_io_r(VGA_IS1_RC);
0649     vga_io_w(VGA_ATT_IW, 0x20);
0650 
0651     vga16fb_update_fix(info);
0652     return 0;
0653 }
0654 
0655 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
0656 {
0657     static const unsigned char map[] = { 000, 001, 010, 011 };
0658     int val;
0659     
0660     if (regno >= 16)
0661         return;
0662     val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
0663     vga_io_r(VGA_IS1_RC);   /* ! 0x3BA */
0664     vga_io_wattr(regno, val);
0665     vga_io_r(VGA_IS1_RC);   /* some clones need it */
0666     vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
0667 }
0668 
0669 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
0670 {
0671     outb(regno,       VGA_PEL_IW);
0672     outb(red   >> 10, VGA_PEL_D);
0673     outb(green >> 10, VGA_PEL_D);
0674     outb(blue  >> 10, VGA_PEL_D);
0675 }
0676 
0677 static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
0678                  unsigned blue, unsigned transp,
0679                  struct fb_info *info)
0680 {
0681     struct vga16fb_par *par = info->par;
0682     int gray;
0683 
0684     /*
0685      *  Set a single color register. The values supplied are
0686      *  already rounded down to the hardware's capabilities
0687      *  (according to the entries in the `var' structure). Return
0688      *  != 0 for invalid regno.
0689      */
0690     
0691     if (regno >= 256)
0692         return 1;
0693 
0694     gray = info->var.grayscale;
0695     
0696     if (gray) {
0697         /* gray = 0.30*R + 0.59*G + 0.11*B */
0698         red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
0699     }
0700     if (par->isVGA) 
0701         vga16_setpalette(regno,red,green,blue);
0702     else
0703         ega16_setpalette(regno,red,green,blue);
0704     return 0;
0705 }
0706 
0707 static int vga16fb_pan_display(struct fb_var_screeninfo *var,
0708                    struct fb_info *info) 
0709 {
0710     vga16fb_pan_var(info, var);
0711     return 0;
0712 }
0713 
0714 /* The following VESA blanking code is taken from vgacon.c.  The VGA
0715    blanking code was originally by Huang shi chao, and modified by
0716    Christoph Rimek (chrimek@toppoint.de) and todd j. derr
0717    (tjd@barefoot.org) for Linux. */
0718 
0719 static void vga_vesa_blank(struct vga16fb_par *par, int mode)
0720 {
0721     unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
0722     unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
0723     
0724     /* save original values of VGA controller registers */
0725     if(!par->vesa_blanked) {
0726         par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
0727         //sti();
0728 
0729         par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
0730         par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */
0731         par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);   /* StartHorizRetrace */
0732         par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */
0733         par->vga_state.Overflow = vga_io_rcrt(0x07);        /* Overflow */
0734         par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);    /* StartVertRetrace */
0735         par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);  /* EndVertRetrace */
0736         par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
0737         par->vga_state.ClockingMode = vga_io_rseq(0x01);    /* ClockingMode */
0738     }
0739 
0740     /* assure that video is enabled */
0741     /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
0742     vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
0743 
0744     /* test for vertical retrace in process.... */
0745     if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
0746         vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
0747 
0748     /*
0749      * Set <End of vertical retrace> to minimum (0) and
0750      * <Start of vertical Retrace> to maximum (incl. overflow)
0751      * Result: turn off vertical sync (VSync) pulse.
0752      */
0753     if (mode & FB_BLANK_VSYNC_SUSPEND) {
0754         vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
0755         vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
0756         /* bits 9,10 of vert. retrace */
0757         vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
0758     }
0759 
0760     if (mode & FB_BLANK_HSYNC_SUSPEND) {
0761         /*
0762          * Set <End of horizontal retrace> to minimum (0) and
0763          *  <Start of horizontal Retrace> to maximum
0764          * Result: turn off horizontal sync (HSync) pulse.
0765          */
0766         vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
0767         vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
0768     }
0769 
0770     /* restore both index registers */
0771     outb_p(SeqCtrlIndex, VGA_SEQ_I);
0772     outb_p(CrtCtrlIndex, VGA_CRT_IC);
0773 }
0774 
0775 static void vga_vesa_unblank(struct vga16fb_par *par)
0776 {
0777     unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
0778     unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
0779     
0780     /* restore original values of VGA controller registers */
0781     vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
0782 
0783     /* HorizontalTotal */
0784     vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
0785     /* HorizDisplayEnd */
0786     vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
0787     /* StartHorizRetrace */
0788     vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
0789     /* EndHorizRetrace */
0790     vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
0791     /* Overflow */
0792     vga_io_wcrt(0x07, par->vga_state.Overflow);
0793     /* StartVertRetrace */
0794     vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
0795     /* EndVertRetrace */
0796     vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
0797     /* ModeControl */
0798     vga_io_wcrt(0x17, par->vga_state.ModeControl);
0799     /* ClockingMode */
0800     vga_io_wseq(0x01, par->vga_state.ClockingMode);
0801 
0802     /* restore index/control registers */
0803     vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
0804     vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
0805 }
0806 
0807 static void vga_pal_blank(void)
0808 {
0809     int i;
0810 
0811     for (i=0; i<16; i++) {
0812         outb_p(i, VGA_PEL_IW);
0813         outb_p(0, VGA_PEL_D);
0814         outb_p(0, VGA_PEL_D);
0815         outb_p(0, VGA_PEL_D);
0816     }
0817 }
0818 
0819 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
0820 static int vga16fb_blank(int blank, struct fb_info *info)
0821 {
0822     struct vga16fb_par *par = info->par;
0823 
0824     switch (blank) {
0825     case FB_BLANK_UNBLANK:              /* Unblank */
0826         if (par->vesa_blanked) {
0827             vga_vesa_unblank(par);
0828             par->vesa_blanked = 0;
0829         }
0830         if (par->palette_blanked) {
0831             par->palette_blanked = 0;
0832         }
0833         break;
0834     case FB_BLANK_NORMAL:               /* blank */
0835         vga_pal_blank();
0836         par->palette_blanked = 1;
0837         break;
0838     default:            /* VESA blanking */
0839         vga_vesa_blank(par, blank);
0840         par->vesa_blanked = 1;
0841         break;
0842     }
0843     return 0;
0844 }
0845 
0846 static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0847 {
0848     u32 dx = rect->dx, width = rect->width;
0849         char oldindex = getindex();
0850         char oldmode = setmode(0x40);
0851         char oldmask = selectmask();
0852         int line_ofs, height;
0853         char oldop, oldsr;
0854         char __iomem *where;
0855 
0856         dx /= 4;
0857         where = info->screen_base + dx + rect->dy * info->fix.line_length;
0858 
0859         if (rect->rop == ROP_COPY) {
0860                 oldop = setop(0);
0861                 oldsr = setsr(0);
0862 
0863                 width /= 4;
0864                 line_ofs = info->fix.line_length - width;
0865                 setmask(0xff);
0866 
0867                 height = rect->height;
0868 
0869                 while (height--) {
0870                         int x;
0871 
0872                         /* we can do memset... */
0873                         for (x = width; x > 0; --x) {
0874                                 writeb(rect->color, where);
0875                                 where++;
0876                         }
0877                         where += line_ofs;
0878                 }
0879         } else {
0880                 char oldcolor = setcolor(0xf);
0881                 int y;
0882 
0883                 oldop = setop(0x18);
0884                 oldsr = setsr(0xf);
0885                 setmask(0x0F);
0886                 for (y = 0; y < rect->height; y++) {
0887                         rmw(where);
0888                         rmw(where+1);
0889                         where += info->fix.line_length;
0890                 }
0891                 setcolor(oldcolor);
0892         }
0893         setmask(oldmask);
0894         setsr(oldsr);
0895         setop(oldop);
0896         setmode(oldmode);
0897         setindex(oldindex);
0898 }
0899 
0900 static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0901 {
0902     int x, x2, y2, vxres, vyres, width, height, line_ofs;
0903     char __iomem *dst;
0904 
0905     vxres = info->var.xres_virtual;
0906     vyres = info->var.yres_virtual;
0907 
0908     if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
0909         return;
0910 
0911     /* We could use hardware clipping but on many cards you get around
0912      * hardware clipping by writing to framebuffer directly. */
0913 
0914     x2 = rect->dx + rect->width;
0915     y2 = rect->dy + rect->height;
0916     x2 = x2 < vxres ? x2 : vxres;
0917     y2 = y2 < vyres ? y2 : vyres;
0918     width = x2 - rect->dx;
0919 
0920     switch (info->fix.type) {
0921     case FB_TYPE_VGA_PLANES:
0922         if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
0923 
0924             height = y2 - rect->dy;
0925             width = rect->width/8;
0926 
0927             line_ofs = info->fix.line_length - width;
0928             dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
0929 
0930             switch (rect->rop) {
0931             case ROP_COPY:
0932                 setmode(0);
0933                 setop(0);
0934                 setsr(0xf);
0935                 setcolor(rect->color);
0936                 selectmask();
0937 
0938                 setmask(0xff);
0939 
0940                 while (height--) {
0941                     for (x = 0; x < width; x++) {
0942                         writeb(0, dst);
0943                         dst++;
0944                     }
0945                     dst += line_ofs;
0946                 }
0947                 break;
0948             case ROP_XOR:
0949                 setmode(0);
0950                 setop(0x18);
0951                 setsr(0xf);
0952                 setcolor(0xf);
0953                 selectmask();
0954 
0955                 setmask(0xff);
0956                 while (height--) {
0957                     for (x = 0; x < width; x++) {
0958                         rmw(dst);
0959                         dst++;
0960                     }
0961                     dst += line_ofs;
0962                 }
0963                 break;
0964             }
0965         } else 
0966             vga_8planes_fillrect(info, rect);
0967         break;
0968     case FB_TYPE_PACKED_PIXELS:
0969     default:
0970         cfb_fillrect(info, rect);
0971         break;
0972     }
0973 }
0974 
0975 static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
0976 {
0977         char oldindex = getindex();
0978         char oldmode = setmode(0x41);
0979         char oldop = setop(0);
0980         char oldsr = setsr(0xf);
0981         int height, line_ofs, x;
0982     u32 sx, dx, width;
0983     char __iomem *dest;
0984     char __iomem *src;
0985 
0986         height = area->height;
0987 
0988         sx = area->sx / 4;
0989         dx = area->dx / 4;
0990         width = area->width / 4;
0991 
0992         if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
0993                 line_ofs = info->fix.line_length - width;
0994                 dest = info->screen_base + dx + area->dy * info->fix.line_length;
0995                 src = info->screen_base + sx + area->sy * info->fix.line_length;
0996                 while (height--) {
0997                         for (x = 0; x < width; x++) {
0998                                 readb(src);
0999                                 writeb(0, dest);
1000                                 src++;
1001                                 dest++;
1002                         }
1003                         src += line_ofs;
1004                         dest += line_ofs;
1005                 }
1006         } else {
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;
1012                 while (height--) {
1013                         for (x = 0; x < width; x++) {
1014                                 --src;
1015                                 --dest;
1016                                 readb(src);
1017                                 writeb(0, dest);
1018                         }
1019                         src -= line_ofs;
1020                         dest -= line_ofs;
1021                 }
1022         }
1023 
1024         setsr(oldsr);
1025         setop(oldop);
1026         setmode(oldmode);
1027         setindex(oldindex);
1028 }
1029 
1030 static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1031 {
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;
1037 
1038     vxres = info->var.xres_virtual;
1039     vyres = info->var.yres_virtual;
1040 
1041     if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1042         area->sy > vyres)
1043         return;
1044 
1045     /* clip the destination */
1046     old_dx = area->dx;
1047     old_dy = area->dy;
1048 
1049     /*
1050      * We could use hardware clipping but on many cards you get around
1051      * hardware clipping by writing to framebuffer directly.
1052      */
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;
1059     width = x2 - dx;
1060     height = y2 - dy;
1061 
1062     if (sx + dx < old_dx || sy + dy < old_dy)
1063         return;
1064 
1065     /* update sx1,sy1 */
1066     sx += (dx - old_dx);
1067     sy += (dy - old_dy);
1068 
1069     /* the source must be completely inside the virtual screen */
1070     if (sx + width > vxres || sy + height > vyres)
1071         return;
1072 
1073     switch (info->fix.type) {
1074     case FB_TYPE_VGA_PLANES:
1075         if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1076             width = width/8;
1077             line_ofs = info->fix.line_length - width;
1078 
1079             setmode(1);
1080             setop(0);
1081             setsr(0xf);
1082 
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;
1086                 while (height--) {
1087                     for (x = 0; x < width; x++) {
1088                         readb(src);
1089                         writeb(0, dst);
1090                         dst++;
1091                         src++;
1092                     }
1093                     src += line_ofs;
1094                     dst += line_ofs;
1095                 }
1096             } else {
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;
1101                 while (height--) {
1102                     for (x = 0; x < width; x++) {
1103                         dst--;
1104                         src--;
1105                         readb(src);
1106                         writeb(0, dst);
1107                     }
1108                     src -= line_ofs;
1109                     dst -= line_ofs;
1110                 }
1111             }
1112         } else 
1113             vga_8planes_copyarea(info, area);
1114         break;
1115     case FB_TYPE_PACKED_PIXELS:
1116     default:
1117         cfb_copyarea(info, area);
1118         break;
1119     }
1120 }
1121 
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}
1125 
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;
1132 #else
1133 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1134 #endif
1135 
1136 static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1137 {
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;
1144     u32 dx = image->dx;
1145         char __iomem *where;
1146         int y;
1147 
1148         dx /= 4;
1149         where = info->screen_base + dx + image->dy * info->fix.line_length;
1150 
1151         setmask(0xff);
1152         writeb(image->bg_color, where);
1153         readb(where);
1154         selectmask();
1155         setmask(image->fg_color ^ image->bg_color);
1156         setmode(0x42);
1157         setop(0x18);
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);
1160         setmask(oldmask);
1161         setsr(oldsr);
1162         setop(oldop);
1163         setmode(oldmode);
1164         setindex(oldindex);
1165 }
1166 
1167 static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1168 {
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;
1173     char __iomem *dst;
1174     int x, y;
1175 
1176     switch (info->fix.type) {
1177     case FB_TYPE_VGA_PLANES:
1178         if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1179             if (par->isVGA) {
1180                 setmode(2);
1181                 setop(0);
1182                 setsr(0xf);
1183                 setcolor(image->fg_color);
1184                 selectmask();
1185                 
1186                 setmask(0xff);
1187                 writeb(image->bg_color, where);
1188                 rmb();
1189                 readb(where); /* fill latches */
1190                 setmode(3);
1191                 wmb();
1192                 for (y = 0; y < image->height; y++) {
1193                     dst = where;
1194                     for (x = image->width/8; x--;) 
1195                         writeb(*cdat++, dst++);
1196                     where += info->fix.line_length;
1197                 }
1198                 wmb();
1199             } else {
1200                 setmode(0);
1201                 setop(0);
1202                 setsr(0xf);
1203                 setcolor(image->bg_color);
1204                 selectmask();
1205                 
1206                 setmask(0xff);
1207                 for (y = 0; y < image->height; y++) {
1208                     dst = where;
1209                     for (x=image->width/8; x--;){
1210                         rmw(dst);
1211                         setcolor(image->fg_color);
1212                         selectmask();
1213                         if (*cdat) {
1214                             setmask(*cdat++);
1215                             rmw(dst++);
1216                         }
1217                     }
1218                     where += info->fix.line_length;
1219                 }
1220             }
1221         } else 
1222             vga_8planes_imageblit(info, image);
1223         break;
1224     case FB_TYPE_PACKED_PIXELS:
1225     default:
1226         cfb_imageblit(info, image);
1227         break;
1228     }
1229 }
1230 
1231 static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1232 {
1233     /*
1234      * Draw logo 
1235      */
1236     struct vga16fb_par *par = info->par;
1237     char __iomem *where =
1238         info->screen_base + image->dy * info->fix.line_length +
1239         image->dx/8;
1240     const char *cdat = image->data;
1241     char __iomem *dst;
1242     int x, y;
1243 
1244     switch (info->fix.type) {
1245     case FB_TYPE_VGA_PLANES:
1246         if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1247             par->isVGA) {
1248             setsr(0xf);
1249             setop(0);
1250             setmode(0);
1251             
1252             for (y = 0; y < image->height; y++) {
1253                 for (x = 0; x < image->width; x++) {
1254                     dst = where + x/8;
1255 
1256                     setcolor(*cdat);
1257                     selectmask();
1258                     setmask(1 << (7 - (x % 8)));
1259                     fb_readb(dst);
1260                     fb_writeb(0, dst);
1261 
1262                     cdat++;
1263                 }
1264                 where += info->fix.line_length;
1265             }
1266         }
1267         break;
1268     case FB_TYPE_PACKED_PIXELS:
1269         cfb_imageblit(info, image);
1270         break;
1271     default:
1272         break;
1273     }
1274 }
1275                 
1276 static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1277 {
1278     if (image->depth == 1)
1279         vga_imageblit_expand(info, image);
1280     else
1281         vga_imageblit_color(info, image);
1282 }
1283 
1284 static void vga16fb_destroy(struct fb_info *info)
1285 {
1286     iounmap(info->screen_base);
1287     fb_dealloc_cmap(&info->cmap);
1288     /* XXX unshare VGA regions */
1289     framebuffer_release(info);
1290 }
1291 
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,
1305 };
1306 
1307 #ifndef MODULE
1308 static int __init vga16fb_setup(char *options)
1309 {
1310     char *this_opt;
1311     
1312     if (!options || !*options)
1313         return 0;
1314     
1315     while ((this_opt = strsep(&options, ",")) != NULL) {
1316         if (!*this_opt) continue;
1317     }
1318     return 0;
1319 }
1320 #endif
1321 
1322 static int vga16fb_probe(struct platform_device *dev)
1323 {
1324     struct fb_info *info;
1325     struct vga16fb_par *par;
1326     int i;
1327     int ret = 0;
1328 
1329     printk(KERN_DEBUG "vga16fb: initializing\n");
1330     info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1331 
1332     if (!info) {
1333         ret = -ENOMEM;
1334         goto err_fb_alloc;
1335     }
1336     info->apertures = alloc_apertures(1);
1337     if (!info->apertures) {
1338         ret = -ENOMEM;
1339         goto err_ioremap;
1340     }
1341 
1342     /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1343     info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1344 
1345     if (!info->screen_base) {
1346         printk(KERN_ERR "vga16fb: unable to map device\n");
1347         ret = -ENOMEM;
1348         goto err_ioremap;
1349     }
1350 
1351     printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1352     par = info->par;
1353 
1354 #if defined(CONFIG_X86)
1355     par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC;
1356 #else
1357     /* non-x86 architectures treat orig_video_isVGA as a boolean flag */
1358     par->isVGA = screen_info.orig_video_isVGA;
1359 #endif
1360     par->palette_blanked = 0;
1361     par->vesa_blanked = 0;
1362 
1363     i = par->isVGA? 6 : 2;
1364     
1365     vga16fb_defined.red.length   = i;
1366     vga16fb_defined.green.length = i;
1367     vga16fb_defined.blue.length  = i;   
1368 
1369     /* name should not depend on EGA/VGA */
1370     info->fbops = &vga16fb_ops;
1371     info->var = vga16fb_defined;
1372     info->fix = vga16fb_fix;
1373     /* supports rectangles with widths of multiples of 8 */
1374     info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1375     info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
1376         FBINFO_HWACCEL_YPAN;
1377 
1378     i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1379     ret = fb_alloc_cmap(&info->cmap, i, 0);
1380     if (ret) {
1381         printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1382         ret = -ENOMEM;
1383         goto err_alloc_cmap;
1384     }
1385 
1386     if (vga16fb_check_var(&info->var, info)) {
1387         printk(KERN_ERR "vga16fb: unable to validate variable\n");
1388         ret = -EINVAL;
1389         goto err_check_var;
1390     }
1391 
1392     vga16fb_update_fix(info);
1393 
1394     info->apertures->ranges[0].base = VGA_FB_PHYS;
1395     info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
1396 
1397     if (register_framebuffer(info) < 0) {
1398         printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1399         ret = -EINVAL;
1400         goto err_check_var;
1401     }
1402 
1403     fb_info(info, "%s frame buffer device\n", info->fix.id);
1404     platform_set_drvdata(dev, info);
1405 
1406     return 0;
1407 
1408  err_check_var:
1409     fb_dealloc_cmap(&info->cmap);
1410  err_alloc_cmap:
1411     iounmap(info->screen_base);
1412  err_ioremap:
1413     framebuffer_release(info);
1414  err_fb_alloc:
1415     return ret;
1416 }
1417 
1418 static int vga16fb_remove(struct platform_device *dev)
1419 {
1420     struct fb_info *info = platform_get_drvdata(dev);
1421 
1422     if (info)
1423         unregister_framebuffer(info);
1424 
1425     return 0;
1426 }
1427 
1428 static struct platform_driver vga16fb_driver = {
1429     .probe = vga16fb_probe,
1430     .remove = vga16fb_remove,
1431     .driver = {
1432         .name = "vga16fb",
1433     },
1434 };
1435 
1436 static struct platform_device *vga16fb_device;
1437 
1438 static int __init vga16fb_init(void)
1439 {
1440     int ret;
1441 #ifndef MODULE
1442     char *option = NULL;
1443 
1444     if (fb_get_options("vga16fb", &option))
1445         return -ENODEV;
1446 
1447     vga16fb_setup(option);
1448 #endif
1449 
1450     ret = check_mode_supported();
1451     if (ret)
1452         return ret;
1453 
1454     ret = platform_driver_register(&vga16fb_driver);
1455 
1456     if (!ret) {
1457         vga16fb_device = platform_device_alloc("vga16fb", 0);
1458 
1459         if (vga16fb_device)
1460             ret = platform_device_add(vga16fb_device);
1461         else
1462             ret = -ENOMEM;
1463 
1464         if (ret) {
1465             platform_device_put(vga16fb_device);
1466             platform_driver_unregister(&vga16fb_driver);
1467         }
1468     }
1469 
1470     return ret;
1471 }
1472 
1473 static void __exit vga16fb_exit(void)
1474 {
1475     platform_device_unregister(vga16fb_device);
1476     platform_driver_unregister(&vga16fb_driver);
1477 }
1478 
1479 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1480 MODULE_LICENSE("GPL");
1481 module_init(vga16fb_init);
1482 module_exit(vga16fb_exit);