linux/drivers/video/fbdev/vga16fb.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
   3 * 
   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>
   7 *
   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.  
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/errno.h>
  16#include <linux/string.h>
  17#include <linux/mm.h>
  18#include <linux/delay.h>
  19#include <linux/fb.h>
  20#include <linux/ioport.h>
  21#include <linux/init.h>
  22#include <linux/platform_device.h>
  23#include <linux/screen_info.h>
  24
  25#include <asm/io.h>
  26#include <video/vga.h>
  27
  28#define VGA_FB_PHYS 0xA0000
  29#define VGA_FB_PHYS_LEN 65536
  30
  31#define MODE_SKIP4      1
  32#define MODE_8BPP       2
  33#define MODE_CFB        4
  34#define MODE_TEXT       8
  35
  36/* --------------------------------------------------------------------- */
  37
  38/*
  39 * card parameters
  40 */
  41
  42struct vga16fb_par {
  43        /* structure holding original VGA register settings when the
  44           screen is blanked */
  45        struct {
  46                unsigned char   SeqCtrlIndex;     /* Sequencer Index reg.   */
  47                unsigned char   CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
  48                unsigned char   CrtMiscIO;        /* Miscellaneous register */
  49                unsigned char   HorizontalTotal;  /* CRT-Controller:00h */
  50                unsigned char   HorizDisplayEnd;  /* CRT-Controller:01h */
  51                unsigned char   StartHorizRetrace;/* CRT-Controller:04h */
  52                unsigned char   EndHorizRetrace;  /* CRT-Controller:05h */
  53                unsigned char   Overflow;         /* CRT-Controller:07h */
  54                unsigned char   StartVertRetrace; /* CRT-Controller:10h */
  55                unsigned char   EndVertRetrace;   /* CRT-Controller:11h */
  56                unsigned char   ModeControl;      /* CRT-Controller:17h */
  57                unsigned char   ClockingMode;     /* Seq-Controller:01h */
  58        } vga_state;
  59        struct vgastate state;
  60        unsigned int ref_count;
  61        int palette_blanked, vesa_blanked, mode, isVGA;
  62        u8 misc, pel_msk, vss, clkdiv;
  63        u8 crtc[VGA_CRT_C];
  64};
  65
  66/* --------------------------------------------------------------------- */
  67
  68static struct fb_var_screeninfo vga16fb_defined = {
  69        .xres           = 640,
  70        .yres           = 480,
  71        .xres_virtual   = 640,
  72        .yres_virtual   = 480,
  73        .bits_per_pixel = 4,    
  74        .activate       = FB_ACTIVATE_TEST,
  75        .height         = -1,
  76        .width          = -1,
  77        .pixclock       = 39721,
  78        .left_margin    = 48,
  79        .right_margin   = 16,
  80        .upper_margin   = 33,
  81        .lower_margin   = 10,
  82        .hsync_len      = 96,
  83        .vsync_len      = 2,
  84        .vmode          = FB_VMODE_NONINTERLACED,
  85};
  86
  87/* name should not depend on EGA/VGA */
  88static const struct fb_fix_screeninfo vga16fb_fix = {
  89        .id             = "VGA16 VGA",
  90        .smem_start     = VGA_FB_PHYS,
  91        .smem_len       = VGA_FB_PHYS_LEN,
  92        .type           = FB_TYPE_VGA_PLANES,
  93        .type_aux       = FB_AUX_VGA_PLANES_VGA4,
  94        .visual         = FB_VISUAL_PSEUDOCOLOR,
  95        .xpanstep       = 8,
  96        .ypanstep       = 1,
  97        .line_length    = 640 / 8,
  98        .accel          = FB_ACCEL_NONE
  99};
 100
 101/* The VGA's weird architecture often requires that we read a byte and
 102   write a byte to the same location.  It doesn't matter *what* byte
 103   we write, however.  This is because all the action goes on behind
 104   the scenes in the VGA's 32-bit latch register, and reading and writing
 105   video memory just invokes latch behavior.
 106
 107   To avoid race conditions (is this necessary?), reading and writing
 108   the memory byte should be done with a single instruction.  One
 109   suitable instruction is the x86 bitwise OR.  The following
 110   read-modify-write routine should optimize to one such bitwise
 111   OR. */
 112static inline void rmw(volatile char __iomem *p)
 113{
 114        readb(p);
 115        writeb(1, p);
 116}
 117
 118/* Set the Graphics Mode Register, and return its previous value.
 119   Bits 0-1 are write mode, bit 3 is read mode. */
 120static inline int setmode(int mode)
 121{
 122        int oldmode;
 123        
 124        oldmode = vga_io_rgfx(VGA_GFX_MODE);
 125        vga_io_w(VGA_GFX_D, mode);
 126        return oldmode;
 127}
 128
 129/* Select the Bit Mask Register and return its value. */
 130static inline int selectmask(void)
 131{
 132        return vga_io_rgfx(VGA_GFX_BIT_MASK);
 133}
 134
 135/* Set the value of the Bit Mask Register.  It must already have been
 136   selected with selectmask(). */
 137static inline void setmask(int mask)
 138{
 139        vga_io_w(VGA_GFX_D, mask);
 140}
 141
 142/* Set the Data Rotate Register and return its old value. 
 143   Bits 0-2 are rotate count, bits 3-4 are logical operation
 144   (0=NOP, 1=AND, 2=OR, 3=XOR). */
 145static inline int setop(int op)
 146{
 147        int oldop;
 148        
 149        oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
 150        vga_io_w(VGA_GFX_D, op);
 151        return oldop;
 152}
 153
 154/* Set the Enable Set/Reset Register and return its old value.  
 155   The code here always uses value 0xf for this register. */
 156static inline int setsr(int sr)
 157{
 158        int oldsr;
 159
 160        oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
 161        vga_io_w(VGA_GFX_D, sr);
 162        return oldsr;
 163}
 164
 165/* Set the Set/Reset Register and return its old value. */
 166static inline int setcolor(int color)
 167{
 168        int oldcolor;
 169
 170        oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
 171        vga_io_w(VGA_GFX_D, color);
 172        return oldcolor;
 173}
 174
 175/* Return the value in the Graphics Address Register. */
 176static inline int getindex(void)
 177{
 178        return vga_io_r(VGA_GFX_I);
 179}
 180
 181/* Set the value in the Graphics Address Register. */
 182static inline void setindex(int index)
 183{
 184        vga_io_w(VGA_GFX_I, index);
 185}
 186
 187static void vga16fb_pan_var(struct fb_info *info, 
 188                            struct fb_var_screeninfo *var)
 189{
 190        struct vga16fb_par *par = info->par;
 191        u32 xoffset, pos;
 192
 193        xoffset = var->xoffset;
 194        if (info->var.bits_per_pixel == 8) {
 195                pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
 196        } else if (par->mode & MODE_TEXT) {
 197                int fh = 16; // FIXME !!! font height. Fugde for now.
 198                pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
 199        } else {
 200                if (info->var.nonstd)
 201                        xoffset--;
 202                pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
 203        }
 204        vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
 205        vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
 206        /* if we support CFB4, then we must! support xoffset with pixel
 207         * granularity if someone supports xoffset in bit resolution */
 208        vga_io_r(VGA_IS1_RC);           /* reset flip-flop */
 209        vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
 210        if (info->var.bits_per_pixel == 8)
 211                vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
 212        else
 213                vga_io_w(VGA_ATT_IW, xoffset & 7);
 214        vga_io_r(VGA_IS1_RC);
 215        vga_io_w(VGA_ATT_IW, 0x20);
 216}
 217
 218static void vga16fb_update_fix(struct fb_info *info)
 219{
 220        if (info->var.bits_per_pixel == 4) {
 221                if (info->var.nonstd) {
 222                        info->fix.type = FB_TYPE_PACKED_PIXELS;
 223                        info->fix.line_length = info->var.xres_virtual / 2;
 224                } else {
 225                        info->fix.type = FB_TYPE_VGA_PLANES;
 226                        info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
 227                        info->fix.line_length = info->var.xres_virtual / 8;
 228                }
 229        } else if (info->var.bits_per_pixel == 0) {
 230                info->fix.type = FB_TYPE_TEXT;
 231                info->fix.type_aux = FB_AUX_TEXT_CGA;
 232                info->fix.line_length = info->var.xres_virtual / 4;
 233        } else {        /* 8bpp */
 234                if (info->var.nonstd) {
 235                        info->fix.type = FB_TYPE_VGA_PLANES;
 236                        info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
 237                        info->fix.line_length = info->var.xres_virtual / 4;
 238                } else {
 239                        info->fix.type = FB_TYPE_PACKED_PIXELS;
 240                        info->fix.line_length = info->var.xres_virtual;
 241                }
 242        }
 243}
 244
 245static void vga16fb_clock_chip(struct vga16fb_par *par,
 246                               unsigned int *pixclock,
 247                               const struct fb_info *info,
 248                               int mul, int div)
 249{
 250        static const struct {
 251                u32 pixclock;
 252                u8  misc;
 253                u8  seq_clock_mode;
 254        } *ptr, *best, vgaclocks[] = {
 255                { 79442 /* 12.587 */, 0x00, 0x08},
 256                { 70616 /* 14.161 */, 0x04, 0x08},
 257                { 39721 /* 25.175 */, 0x00, 0x00},
 258                { 35308 /* 28.322 */, 0x04, 0x00},
 259                {     0 /* bad */,    0x00, 0x00}};
 260        int err;
 261
 262        *pixclock = (*pixclock * mul) / div;
 263        best = vgaclocks;
 264        err = *pixclock - best->pixclock;
 265        if (err < 0) err = -err;
 266        for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
 267                int tmp;
 268
 269                tmp = *pixclock - ptr->pixclock;
 270                if (tmp < 0) tmp = -tmp;
 271                if (tmp < err) {
 272                        err = tmp;
 273                        best = ptr;
 274                }
 275        }
 276        par->misc |= best->misc;
 277        par->clkdiv = best->seq_clock_mode;
 278        *pixclock = (best->pixclock * div) / mul;
 279}
 280                               
 281#define FAIL(X) return -EINVAL
 282
 283static int vga16fb_open(struct fb_info *info, int user)
 284{
 285        struct vga16fb_par *par = info->par;
 286
 287        if (!par->ref_count) {
 288                memset(&par->state, 0, sizeof(struct vgastate));
 289                par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
 290                        VGA_SAVE_CMAP;
 291                save_vga(&par->state);
 292        }
 293        par->ref_count++;
 294
 295        return 0;
 296}
 297
 298static int vga16fb_release(struct fb_info *info, int user)
 299{
 300        struct vga16fb_par *par = info->par;
 301
 302        if (!par->ref_count)
 303                return -EINVAL;
 304
 305        if (par->ref_count == 1)
 306                restore_vga(&par->state);
 307        par->ref_count--;
 308
 309        return 0;
 310}
 311
 312static int vga16fb_check_var(struct fb_var_screeninfo *var,
 313                             struct fb_info *info)
 314{
 315        struct vga16fb_par *par = info->par;
 316        u32 xres, right, hslen, left, xtotal;
 317        u32 yres, lower, vslen, upper, ytotal;
 318        u32 vxres, xoffset, vyres, yoffset;
 319        u32 pos;
 320        u8 r7, rMode;
 321        int shift;
 322        int mode;
 323        u32 maxmem;
 324
 325        par->pel_msk = 0xFF;
 326
 327        if (var->bits_per_pixel == 4) {
 328                if (var->nonstd) {
 329                        if (!par->isVGA)
 330                                return -EINVAL;
 331                        shift = 3;
 332                        mode = MODE_SKIP4 | MODE_CFB;
 333                        maxmem = 16384;
 334                        par->pel_msk = 0x0F;
 335                } else {
 336                        shift = 3;
 337                        mode = 0;
 338                        maxmem = 65536;
 339                }
 340        } else if (var->bits_per_pixel == 8) {
 341                if (!par->isVGA)
 342                        return -EINVAL; /* no support on EGA */
 343                shift = 2;
 344                if (var->nonstd) {
 345                        mode = MODE_8BPP | MODE_CFB;
 346                        maxmem = 65536;
 347                } else {
 348                        mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
 349                        maxmem = 16384;
 350                }
 351        } else
 352                return -EINVAL;
 353
 354        xres = (var->xres + 7) & ~7;
 355        vxres = (var->xres_virtual + 0xF) & ~0xF;
 356        xoffset = (var->xoffset + 7) & ~7;
 357        left = (var->left_margin + 7) & ~7;
 358        right = (var->right_margin + 7) & ~7;
 359        hslen = (var->hsync_len + 7) & ~7;
 360
 361        if (vxres < xres)
 362                vxres = xres;
 363        if (xres + xoffset > vxres)
 364                xoffset = vxres - xres;
 365
 366        var->xres = xres;
 367        var->right_margin = right;
 368        var->hsync_len = hslen;
 369        var->left_margin = left;
 370        var->xres_virtual = vxres;
 371        var->xoffset = xoffset;
 372
 373        xres >>= shift;
 374        right >>= shift;
 375        hslen >>= shift;
 376        left >>= shift;
 377        vxres >>= shift;
 378        xtotal = xres + right + hslen + left;
 379        if (xtotal >= 256)
 380                FAIL("xtotal too big");
 381        if (hslen > 32)
 382                FAIL("hslen too big");
 383        if (right + hslen + left > 64)
 384                FAIL("hblank too big");
 385        par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
 386        par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
 387        par->crtc[VGA_CRTC_H_DISP] = xres - 1;
 388        pos = xres + right;
 389        par->crtc[VGA_CRTC_H_SYNC_START] = pos;
 390        pos += hslen;
 391        par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
 392        pos += left - 2; /* blank_end + 2 <= total + 5 */
 393        par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
 394        if (pos & 0x20)
 395                par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
 396
 397        yres = var->yres;
 398        lower = var->lower_margin;
 399        vslen = var->vsync_len;
 400        upper = var->upper_margin;
 401        vyres = var->yres_virtual;
 402        yoffset = var->yoffset;
 403
 404        if (yres > vyres)
 405                vyres = yres;
 406        if (vxres * vyres > maxmem) {
 407                vyres = maxmem / vxres;
 408                if (vyres < yres)
 409                        return -ENOMEM;
 410        }
 411        if (yoffset + yres > vyres)
 412                yoffset = vyres - yres;
 413        var->yres = yres;
 414        var->lower_margin = lower;
 415        var->vsync_len = vslen;
 416        var->upper_margin = upper;
 417        var->yres_virtual = vyres;
 418        var->yoffset = yoffset;
 419
 420        if (var->vmode & FB_VMODE_DOUBLE) {
 421                yres <<= 1;
 422                lower <<= 1;
 423                vslen <<= 1;
 424                upper <<= 1;
 425        }
 426        ytotal = yres + lower + vslen + upper;
 427        if (ytotal > 1024) {
 428                ytotal >>= 1;
 429                yres >>= 1;
 430                lower >>= 1;
 431                vslen >>= 1;
 432                upper >>= 1;
 433                rMode = 0x04;
 434        } else
 435                rMode = 0x00;
 436        if (ytotal > 1024)
 437                FAIL("ytotal too big");
 438        if (vslen > 16)
 439                FAIL("vslen too big");
 440        par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
 441        r7 = 0x10;      /* disable linecompare */
 442        if (ytotal & 0x100) r7 |= 0x01;
 443        if (ytotal & 0x200) r7 |= 0x20;
 444        par->crtc[VGA_CRTC_PRESET_ROW] = 0;
 445        par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;    /* 1 scanline, no linecmp */
 446        if (var->vmode & FB_VMODE_DOUBLE)
 447                par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
 448        par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
 449        par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
 450        if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
 451                xoffset--;
 452        pos = yoffset * vxres + (xoffset >> shift);
 453        par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
 454        par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
 455        par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
 456        par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
 457        pos = yres - 1;
 458        par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
 459        par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
 460        if (pos & 0x100)
 461                r7 |= 0x0A;     /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
 462        if (pos & 0x200) {
 463                r7 |= 0x40;     /* 0x40 -> DISP_END */
 464                par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
 465        }
 466        pos += lower;
 467        par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
 468        if (pos & 0x100)
 469                r7 |= 0x04;
 470        if (pos & 0x200)
 471                r7 |= 0x80;
 472        pos += vslen;
 473        par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
 474        pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
 475        par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
 476                     but some SVGA chips requires all 8 bits to set */
 477        if (vxres >= 512)
 478                FAIL("vxres too long");
 479        par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
 480        if (mode & MODE_SKIP4)
 481                par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;   /* 256, cfb8 */
 482        else
 483                par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;   /* 16, vgap */
 484        par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
 485        par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
 486        par->crtc[VGA_CRTC_OVERFLOW] = r7;
 487
 488        par->vss = 0x00;        /* 3DA */
 489
 490        par->misc = 0xE3;       /* enable CPU, ports 0x3Dx, positive sync */
 491        if (var->sync & FB_SYNC_HOR_HIGH_ACT)
 492                par->misc &= ~0x40;
 493        if (var->sync & FB_SYNC_VERT_HIGH_ACT)
 494                par->misc &= ~0x80;
 495        
 496        par->mode = mode;
 497
 498        if (mode & MODE_8BPP)
 499                /* pixel clock == vga clock / 2 */
 500                vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
 501        else
 502                /* pixel clock == vga clock */
 503                vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
 504        
 505        var->red.offset = var->green.offset = var->blue.offset = 
 506        var->transp.offset = 0;
 507        var->red.length = var->green.length = var->blue.length =
 508                (par->isVGA) ? 6 : 2;
 509        var->transp.length = 0;
 510        var->activate = FB_ACTIVATE_NOW;
 511        var->height = -1;
 512        var->width = -1;
 513        var->accel_flags = 0;
 514        return 0;
 515}
 516#undef FAIL
 517
 518static int vga16fb_set_par(struct fb_info *info)
 519{
 520        struct vga16fb_par *par = info->par;
 521        u8 gdc[VGA_GFX_C];
 522        u8 seq[VGA_SEQ_C];
 523        u8 atc[VGA_ATT_C];
 524        int fh, i;
 525
 526        seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
 527        if (par->mode & MODE_TEXT)
 528                seq[VGA_SEQ_PLANE_WRITE] = 0x03;
 529        else
 530                seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
 531        seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
 532        if (par->mode & MODE_TEXT)
 533                seq[VGA_SEQ_MEMORY_MODE] = 0x03;
 534        else if (par->mode & MODE_SKIP4)
 535                seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
 536        else
 537                seq[VGA_SEQ_MEMORY_MODE] = 0x06;
 538
 539        gdc[VGA_GFX_SR_VALUE] = 0x00;
 540        gdc[VGA_GFX_SR_ENABLE] = 0x00;
 541        gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
 542        gdc[VGA_GFX_DATA_ROTATE] = 0x00;
 543        gdc[VGA_GFX_PLANE_READ] = 0;
 544        if (par->mode & MODE_TEXT) {
 545                gdc[VGA_GFX_MODE] = 0x10;
 546                gdc[VGA_GFX_MISC] = 0x06;
 547        } else {
 548                if (par->mode & MODE_CFB)
 549                        gdc[VGA_GFX_MODE] = 0x40;
 550                else
 551                        gdc[VGA_GFX_MODE] = 0x00;
 552                gdc[VGA_GFX_MISC] = 0x05;
 553        }
 554        gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
 555        gdc[VGA_GFX_BIT_MASK] = 0xFF;
 556
 557        for (i = 0x00; i < 0x10; i++)
 558                atc[i] = i;
 559        if (par->mode & MODE_TEXT)
 560                atc[VGA_ATC_MODE] = 0x04;
 561        else if (par->mode & MODE_8BPP)
 562                atc[VGA_ATC_MODE] = 0x41;
 563        else
 564                atc[VGA_ATC_MODE] = 0x81;
 565        atc[VGA_ATC_OVERSCAN] = 0x00;   /* 0 for EGA, 0xFF for VGA */
 566        atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
 567        if (par->mode & MODE_8BPP)
 568                atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
 569        else
 570                atc[VGA_ATC_PEL] = info->var.xoffset & 7;
 571        atc[VGA_ATC_COLOR_PAGE] = 0x00;
 572        
 573        if (par->mode & MODE_TEXT) {
 574                fh = 16; // FIXME !!! Fudge font height. 
 575                par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] 
 576                                               & ~0x1F) | (fh - 1);
 577        }
 578
 579        vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
 580
 581        /* Enable graphics register modification */
 582        if (!par->isVGA) {
 583                vga_io_w(EGA_GFX_E0, 0x00);
 584                vga_io_w(EGA_GFX_E1, 0x01);
 585        }
 586        
 587        /* update misc output register */
 588        vga_io_w(VGA_MIS_W, par->misc);
 589        
 590        /* synchronous reset on */
 591        vga_io_wseq(0x00, 0x01);
 592
 593        if (par->isVGA)
 594                vga_io_w(VGA_PEL_MSK, par->pel_msk);
 595
 596        /* write sequencer registers */
 597        vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
 598        for (i = 2; i < VGA_SEQ_C; i++) {
 599                vga_io_wseq(i, seq[i]);
 600        }
 601        
 602        /* synchronous reset off */
 603        vga_io_wseq(0x00, 0x03);
 604
 605        /* deprotect CRT registers 0-7 */
 606        vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
 607
 608        /* write CRT registers */
 609        for (i = 0; i < VGA_CRTC_REGS; i++) {
 610                vga_io_wcrt(i, par->crtc[i]);
 611        }
 612        
 613        /* write graphics controller registers */
 614        for (i = 0; i < VGA_GFX_C; i++) {
 615                vga_io_wgfx(i, gdc[i]);
 616        }
 617        
 618        /* write attribute controller registers */
 619        for (i = 0; i < VGA_ATT_C; i++) {
 620                vga_io_r(VGA_IS1_RC);           /* reset flip-flop */
 621                vga_io_wattr(i, atc[i]);
 622        }
 623
 624        /* Wait for screen to stabilize. */
 625        mdelay(50);
 626
 627        vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
 628
 629        vga_io_r(VGA_IS1_RC);
 630        vga_io_w(VGA_ATT_IW, 0x20);
 631
 632        vga16fb_update_fix(info);
 633        return 0;
 634}
 635
 636static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
 637{
 638        static const unsigned char map[] = { 000, 001, 010, 011 };
 639        int val;
 640        
 641        if (regno >= 16)
 642                return;
 643        val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
 644        vga_io_r(VGA_IS1_RC);   /* ! 0x3BA */
 645        vga_io_wattr(regno, val);
 646        vga_io_r(VGA_IS1_RC);   /* some clones need it */
 647        vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
 648}
 649
 650static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
 651{
 652        outb(regno,       VGA_PEL_IW);
 653        outb(red   >> 10, VGA_PEL_D);
 654        outb(green >> 10, VGA_PEL_D);
 655        outb(blue  >> 10, VGA_PEL_D);
 656}
 657
 658static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 659                             unsigned blue, unsigned transp,
 660                             struct fb_info *info)
 661{
 662        struct vga16fb_par *par = info->par;
 663        int gray;
 664
 665        /*
 666         *  Set a single color register. The values supplied are
 667         *  already rounded down to the hardware's capabilities
 668         *  (according to the entries in the `var' structure). Return
 669         *  != 0 for invalid regno.
 670         */
 671        
 672        if (regno >= 256)
 673                return 1;
 674
 675        gray = info->var.grayscale;
 676        
 677        if (gray) {
 678                /* gray = 0.30*R + 0.59*G + 0.11*B */
 679                red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
 680        }
 681        if (par->isVGA) 
 682                vga16_setpalette(regno,red,green,blue);
 683        else
 684                ega16_setpalette(regno,red,green,blue);
 685        return 0;
 686}
 687
 688static int vga16fb_pan_display(struct fb_var_screeninfo *var,
 689                               struct fb_info *info) 
 690{
 691        vga16fb_pan_var(info, var);
 692        return 0;
 693}
 694
 695/* The following VESA blanking code is taken from vgacon.c.  The VGA
 696   blanking code was originally by Huang shi chao, and modified by
 697   Christoph Rimek (chrimek@toppoint.de) and todd j. derr
 698   (tjd@barefoot.org) for Linux. */
 699
 700static void vga_vesa_blank(struct vga16fb_par *par, int mode)
 701{
 702        unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
 703        unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
 704        
 705        /* save original values of VGA controller registers */
 706        if(!par->vesa_blanked) {
 707                par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
 708                //sti();
 709
 710                par->vga_state.HorizontalTotal = vga_io_rcrt(0x00);     /* HorizontalTotal */
 711                par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01);     /* HorizDisplayEnd */
 712                par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);   /* StartHorizRetrace */
 713                par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05);     /* EndHorizRetrace */
 714                par->vga_state.Overflow = vga_io_rcrt(0x07);            /* Overflow */
 715                par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);    /* StartVertRetrace */
 716                par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);      /* EndVertRetrace */
 717                par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
 718                par->vga_state.ClockingMode = vga_io_rseq(0x01);        /* ClockingMode */
 719        }
 720
 721        /* assure that video is enabled */
 722        /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
 723        vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
 724
 725        /* test for vertical retrace in process.... */
 726        if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
 727                vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
 728
 729        /*
 730         * Set <End of vertical retrace> to minimum (0) and
 731         * <Start of vertical Retrace> to maximum (incl. overflow)
 732         * Result: turn off vertical sync (VSync) pulse.
 733         */
 734        if (mode & FB_BLANK_VSYNC_SUSPEND) {
 735                vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
 736                vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
 737                /* bits 9,10 of vert. retrace */
 738                vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
 739        }
 740
 741        if (mode & FB_BLANK_HSYNC_SUSPEND) {
 742                /*
 743                 * Set <End of horizontal retrace> to minimum (0) and
 744                 *  <Start of horizontal Retrace> to maximum
 745                 * Result: turn off horizontal sync (HSync) pulse.
 746                 */
 747                vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
 748                vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
 749        }
 750
 751        /* restore both index registers */
 752        outb_p(SeqCtrlIndex, VGA_SEQ_I);
 753        outb_p(CrtCtrlIndex, VGA_CRT_IC);
 754}
 755
 756static void vga_vesa_unblank(struct vga16fb_par *par)
 757{
 758        unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
 759        unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
 760        
 761        /* restore original values of VGA controller registers */
 762        vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
 763
 764        /* HorizontalTotal */
 765        vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
 766        /* HorizDisplayEnd */
 767        vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
 768        /* StartHorizRetrace */
 769        vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
 770        /* EndHorizRetrace */
 771        vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
 772        /* Overflow */
 773        vga_io_wcrt(0x07, par->vga_state.Overflow);
 774        /* StartVertRetrace */
 775        vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
 776        /* EndVertRetrace */
 777        vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
 778        /* ModeControl */
 779        vga_io_wcrt(0x17, par->vga_state.ModeControl);
 780        /* ClockingMode */
 781        vga_io_wseq(0x01, par->vga_state.ClockingMode);
 782
 783        /* restore index/control registers */
 784        vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
 785        vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
 786}
 787
 788static void vga_pal_blank(void)
 789{
 790        int i;
 791
 792        for (i=0; i<16; i++) {
 793                outb_p(i, VGA_PEL_IW);
 794                outb_p(0, VGA_PEL_D);
 795                outb_p(0, VGA_PEL_D);
 796                outb_p(0, VGA_PEL_D);
 797        }
 798}
 799
 800/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
 801static int vga16fb_blank(int blank, struct fb_info *info)
 802{
 803        struct vga16fb_par *par = info->par;
 804
 805        switch (blank) {
 806        case FB_BLANK_UNBLANK:                          /* Unblank */
 807                if (par->vesa_blanked) {
 808                        vga_vesa_unblank(par);
 809                        par->vesa_blanked = 0;
 810                }
 811                if (par->palette_blanked) {
 812                        par->palette_blanked = 0;
 813                }
 814                break;
 815        case FB_BLANK_NORMAL:                           /* blank */
 816                vga_pal_blank();
 817                par->palette_blanked = 1;
 818                break;
 819        default:                        /* VESA blanking */
 820                vga_vesa_blank(par, blank);
 821                par->vesa_blanked = 1;
 822                break;
 823        }
 824        return 0;
 825}
 826
 827static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 828{
 829        u32 dx = rect->dx, width = rect->width;
 830        char oldindex = getindex();
 831        char oldmode = setmode(0x40);
 832        char oldmask = selectmask();
 833        int line_ofs, height;
 834        char oldop, oldsr;
 835        char __iomem *where;
 836
 837        dx /= 4;
 838        where = info->screen_base + dx + rect->dy * info->fix.line_length;
 839
 840        if (rect->rop == ROP_COPY) {
 841                oldop = setop(0);
 842                oldsr = setsr(0);
 843
 844                width /= 4;
 845                line_ofs = info->fix.line_length - width;
 846                setmask(0xff);
 847
 848                height = rect->height;
 849
 850                while (height--) {
 851                        int x;
 852
 853                        /* we can do memset... */
 854                        for (x = width; x > 0; --x) {
 855                                writeb(rect->color, where);
 856                                where++;
 857                        }
 858                        where += line_ofs;
 859                }
 860        } else {
 861                char oldcolor = setcolor(0xf);
 862                int y;
 863
 864                oldop = setop(0x18);
 865                oldsr = setsr(0xf);
 866                setmask(0x0F);
 867                for (y = 0; y < rect->height; y++) {
 868                        rmw(where);
 869                        rmw(where+1);
 870                        where += info->fix.line_length;
 871                }
 872                setcolor(oldcolor);
 873        }
 874        setmask(oldmask);
 875        setsr(oldsr);
 876        setop(oldop);
 877        setmode(oldmode);
 878        setindex(oldindex);
 879}
 880
 881static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 882{
 883        int x, x2, y2, vxres, vyres, width, height, line_ofs;
 884        char __iomem *dst;
 885
 886        vxres = info->var.xres_virtual;
 887        vyres = info->var.yres_virtual;
 888
 889        if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
 890                return;
 891
 892        /* We could use hardware clipping but on many cards you get around
 893         * hardware clipping by writing to framebuffer directly. */
 894
 895        x2 = rect->dx + rect->width;
 896        y2 = rect->dy + rect->height;
 897        x2 = x2 < vxres ? x2 : vxres;
 898        y2 = y2 < vyres ? y2 : vyres;
 899        width = x2 - rect->dx;
 900
 901        switch (info->fix.type) {
 902        case FB_TYPE_VGA_PLANES:
 903                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
 904
 905                        height = y2 - rect->dy;
 906                        width = rect->width/8;
 907
 908                        line_ofs = info->fix.line_length - width;
 909                        dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
 910
 911                        switch (rect->rop) {
 912                        case ROP_COPY:
 913                                setmode(0);
 914                                setop(0);
 915                                setsr(0xf);
 916                                setcolor(rect->color);
 917                                selectmask();
 918
 919                                setmask(0xff);
 920
 921                                while (height--) {
 922                                        for (x = 0; x < width; x++) {
 923                                                writeb(0, dst);
 924                                                dst++;
 925                                        }
 926                                        dst += line_ofs;
 927                                }
 928                                break;
 929                        case ROP_XOR:
 930                                setmode(0);
 931                                setop(0x18);
 932                                setsr(0xf);
 933                                setcolor(0xf);
 934                                selectmask();
 935
 936                                setmask(0xff);
 937                                while (height--) {
 938                                        for (x = 0; x < width; x++) {
 939                                                rmw(dst);
 940                                                dst++;
 941                                        }
 942                                        dst += line_ofs;
 943                                }
 944                                break;
 945                        }
 946                } else 
 947                        vga_8planes_fillrect(info, rect);
 948                break;
 949        case FB_TYPE_PACKED_PIXELS:
 950        default:
 951                cfb_fillrect(info, rect);
 952                break;
 953        }
 954}
 955
 956static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 957{
 958        char oldindex = getindex();
 959        char oldmode = setmode(0x41);
 960        char oldop = setop(0);
 961        char oldsr = setsr(0xf);
 962        int height, line_ofs, x;
 963        u32 sx, dx, width;
 964        char __iomem *dest;
 965        char __iomem *src;
 966
 967        height = area->height;
 968
 969        sx = area->sx / 4;
 970        dx = area->dx / 4;
 971        width = area->width / 4;
 972
 973        if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
 974                line_ofs = info->fix.line_length - width;
 975                dest = info->screen_base + dx + area->dy * info->fix.line_length;
 976                src = info->screen_base + sx + area->sy * info->fix.line_length;
 977                while (height--) {
 978                        for (x = 0; x < width; x++) {
 979                                readb(src);
 980                                writeb(0, dest);
 981                                src++;
 982                                dest++;
 983                        }
 984                        src += line_ofs;
 985                        dest += line_ofs;
 986                }
 987        } else {
 988                line_ofs = info->fix.line_length - width;
 989                dest = info->screen_base + dx + width +
 990                        (area->dy + height - 1) * info->fix.line_length;
 991                src = info->screen_base + sx + width +
 992                        (area->sy + height - 1) * info->fix.line_length;
 993                while (height--) {
 994                        for (x = 0; x < width; x++) {
 995                                --src;
 996                                --dest;
 997                                readb(src);
 998                                writeb(0, dest);
 999                        }
1000                        src -= line_ofs;
1001                        dest -= line_ofs;
1002                }
1003        }
1004
1005        setsr(oldsr);
1006        setop(oldop);
1007        setmode(oldmode);
1008        setindex(oldindex);
1009}
1010
1011static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1012{
1013        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 
1014        int x, x2, y2, old_dx, old_dy, vxres, vyres;
1015        int height, width, line_ofs;
1016        char __iomem *dst = NULL;
1017        char __iomem *src = NULL;
1018
1019        vxres = info->var.xres_virtual;
1020        vyres = info->var.yres_virtual;
1021
1022        if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1023            area->sy > vyres)
1024                return;
1025
1026        /* clip the destination */
1027        old_dx = area->dx;
1028        old_dy = area->dy;
1029
1030        /*
1031         * We could use hardware clipping but on many cards you get around
1032         * hardware clipping by writing to framebuffer directly.
1033         */
1034        x2 = area->dx + area->width;
1035        y2 = area->dy + area->height;
1036        dx = area->dx > 0 ? area->dx : 0;
1037        dy = area->dy > 0 ? area->dy : 0;
1038        x2 = x2 < vxres ? x2 : vxres;
1039        y2 = y2 < vyres ? y2 : vyres;
1040        width = x2 - dx;
1041        height = y2 - dy;
1042
1043        if (sx + dx < old_dx || sy + dy < old_dy)
1044                return;
1045
1046        /* update sx1,sy1 */
1047        sx += (dx - old_dx);
1048        sy += (dy - old_dy);
1049
1050        /* the source must be completely inside the virtual screen */
1051        if (sx + width > vxres || sy + height > vyres)
1052                return;
1053
1054        switch (info->fix.type) {
1055        case FB_TYPE_VGA_PLANES:
1056                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1057                        width = width/8;
1058                        line_ofs = info->fix.line_length - width;
1059
1060                        setmode(1);
1061                        setop(0);
1062                        setsr(0xf);
1063
1064                        if (dy < sy || (dy == sy && dx < sx)) {
1065                                dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1066                                src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1067                                while (height--) {
1068                                        for (x = 0; x < width; x++) {
1069                                                readb(src);
1070                                                writeb(0, dst);
1071                                                dst++;
1072                                                src++;
1073                                        }
1074                                        src += line_ofs;
1075                                        dst += line_ofs;
1076                                }
1077                        } else {
1078                                dst = info->screen_base + (dx/8) + width + 
1079                                        (dy + height - 1) * info->fix.line_length;
1080                                src = info->screen_base + (sx/8) + width + 
1081                                        (sy + height  - 1) * info->fix.line_length;
1082                                while (height--) {
1083                                        for (x = 0; x < width; x++) {
1084                                                dst--;
1085                                                src--;
1086                                                readb(src);
1087                                                writeb(0, dst);
1088                                        }
1089                                        src -= line_ofs;
1090                                        dst -= line_ofs;
1091                                }
1092                        }
1093                } else 
1094                        vga_8planes_copyarea(info, area);
1095                break;
1096        case FB_TYPE_PACKED_PIXELS:
1097        default:
1098                cfb_copyarea(info, area);
1099                break;
1100        }
1101}
1102
1103#define TRANS_MASK_LOW  {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1104#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1105                         0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1106
1107#if defined(__LITTLE_ENDIAN)
1108static const u16 transl_l[] = TRANS_MASK_LOW;
1109static const u16 transl_h[] = TRANS_MASK_HIGH;
1110#elif defined(__BIG_ENDIAN)
1111static const u16 transl_l[] = TRANS_MASK_HIGH;
1112static const u16 transl_h[] = TRANS_MASK_LOW;
1113#else
1114#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1115#endif
1116
1117static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1118{
1119        char oldindex = getindex();
1120        char oldmode = setmode(0x40);
1121        char oldop = setop(0);
1122        char oldsr = setsr(0);
1123        char oldmask = selectmask();
1124        const unsigned char *cdat = image->data;
1125        u32 dx = image->dx;
1126        char __iomem *where;
1127        int y;
1128
1129        dx /= 4;
1130        where = info->screen_base + dx + image->dy * info->fix.line_length;
1131
1132        setmask(0xff);
1133        writeb(image->bg_color, where);
1134        readb(where);
1135        selectmask();
1136        setmask(image->fg_color ^ image->bg_color);
1137        setmode(0x42);
1138        setop(0x18);
1139        for (y = 0; y < image->height; y++, where += info->fix.line_length)
1140                writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1141        setmask(oldmask);
1142        setsr(oldsr);
1143        setop(oldop);
1144        setmode(oldmode);
1145        setindex(oldindex);
1146}
1147
1148static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1149{
1150        char __iomem *where = info->screen_base + (image->dx/8) +
1151                image->dy * info->fix.line_length;
1152        struct vga16fb_par *par = info->par;
1153        char *cdat = (char *) image->data;
1154        char __iomem *dst;
1155        int x, y;
1156
1157        switch (info->fix.type) {
1158        case FB_TYPE_VGA_PLANES:
1159                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1160                        if (par->isVGA) {
1161                                setmode(2);
1162                                setop(0);
1163                                setsr(0xf);
1164                                setcolor(image->fg_color);
1165                                selectmask();
1166                                
1167                                setmask(0xff);
1168                                writeb(image->bg_color, where);
1169                                rmb();
1170                                readb(where); /* fill latches */
1171                                setmode(3);
1172                                wmb();
1173                                for (y = 0; y < image->height; y++) {
1174                                        dst = where;
1175                                        for (x = image->width/8; x--;) 
1176                                                writeb(*cdat++, dst++);
1177                                        where += info->fix.line_length;
1178                                }
1179                                wmb();
1180                        } else {
1181                                setmode(0);
1182                                setop(0);
1183                                setsr(0xf);
1184                                setcolor(image->bg_color);
1185                                selectmask();
1186                                
1187                                setmask(0xff);
1188                                for (y = 0; y < image->height; y++) {
1189                                        dst = where;
1190                                        for (x=image->width/8; x--;){
1191                                                rmw(dst);
1192                                                setcolor(image->fg_color);
1193                                                selectmask();
1194                                                if (*cdat) {
1195                                                        setmask(*cdat++);
1196                                                        rmw(dst++);
1197                                                }
1198                                        }
1199                                        where += info->fix.line_length;
1200                                }
1201                        }
1202                } else 
1203                        vga_8planes_imageblit(info, image);
1204                break;
1205        case FB_TYPE_PACKED_PIXELS:
1206        default:
1207                cfb_imageblit(info, image);
1208                break;
1209        }
1210}
1211
1212static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1213{
1214        /*
1215         * Draw logo 
1216         */
1217        struct vga16fb_par *par = info->par;
1218        char __iomem *where =
1219                info->screen_base + image->dy * info->fix.line_length +
1220                image->dx/8;
1221        const char *cdat = image->data;
1222        char __iomem *dst;
1223        int x, y;
1224
1225        switch (info->fix.type) {
1226        case FB_TYPE_VGA_PLANES:
1227                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1228                    par->isVGA) {
1229                        setsr(0xf);
1230                        setop(0);
1231                        setmode(0);
1232                        
1233                        for (y = 0; y < image->height; y++) {
1234                                for (x = 0; x < image->width; x++) {
1235                                        dst = where + x/8;
1236
1237                                        setcolor(*cdat);
1238                                        selectmask();
1239                                        setmask(1 << (7 - (x % 8)));
1240                                        fb_readb(dst);
1241                                        fb_writeb(0, dst);
1242
1243                                        cdat++;
1244                                }
1245                                where += info->fix.line_length;
1246                        }
1247                }
1248                break;
1249        case FB_TYPE_PACKED_PIXELS:
1250                cfb_imageblit(info, image);
1251                break;
1252        default:
1253                break;
1254        }
1255}
1256                                
1257static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1258{
1259        if (image->depth == 1)
1260                vga_imageblit_expand(info, image);
1261        else
1262                vga_imageblit_color(info, image);
1263}
1264
1265static void vga16fb_destroy(struct fb_info *info)
1266{
1267        iounmap(info->screen_base);
1268        fb_dealloc_cmap(&info->cmap);
1269        /* XXX unshare VGA regions */
1270        framebuffer_release(info);
1271}
1272
1273static const struct fb_ops vga16fb_ops = {
1274        .owner          = THIS_MODULE,
1275        .fb_open        = vga16fb_open,
1276        .fb_release     = vga16fb_release,
1277        .fb_destroy     = vga16fb_destroy,
1278        .fb_check_var   = vga16fb_check_var,
1279        .fb_set_par     = vga16fb_set_par,
1280        .fb_setcolreg   = vga16fb_setcolreg,
1281        .fb_pan_display = vga16fb_pan_display,
1282        .fb_blank       = vga16fb_blank,
1283        .fb_fillrect    = vga16fb_fillrect,
1284        .fb_copyarea    = vga16fb_copyarea,
1285        .fb_imageblit   = vga16fb_imageblit,
1286};
1287
1288#ifndef MODULE
1289static int __init vga16fb_setup(char *options)
1290{
1291        char *this_opt;
1292        
1293        if (!options || !*options)
1294                return 0;
1295        
1296        while ((this_opt = strsep(&options, ",")) != NULL) {
1297                if (!*this_opt) continue;
1298        }
1299        return 0;
1300}
1301#endif
1302
1303static int vga16fb_probe(struct platform_device *dev)
1304{
1305        struct fb_info *info;
1306        struct vga16fb_par *par;
1307        int i;
1308        int ret = 0;
1309
1310        printk(KERN_DEBUG "vga16fb: initializing\n");
1311        info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1312
1313        if (!info) {
1314                ret = -ENOMEM;
1315                goto err_fb_alloc;
1316        }
1317        info->apertures = alloc_apertures(1);
1318        if (!info->apertures) {
1319                ret = -ENOMEM;
1320                goto err_ioremap;
1321        }
1322
1323        /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1324        info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1325
1326        if (!info->screen_base) {
1327                printk(KERN_ERR "vga16fb: unable to map device\n");
1328                ret = -ENOMEM;
1329                goto err_ioremap;
1330        }
1331
1332        printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1333        par = info->par;
1334
1335        par->isVGA = screen_info.orig_video_isVGA;
1336        par->palette_blanked = 0;
1337        par->vesa_blanked = 0;
1338
1339        i = par->isVGA? 6 : 2;
1340        
1341        vga16fb_defined.red.length   = i;
1342        vga16fb_defined.green.length = i;
1343        vga16fb_defined.blue.length  = i;       
1344
1345        /* name should not depend on EGA/VGA */
1346        info->fbops = &vga16fb_ops;
1347        info->var = vga16fb_defined;
1348        info->fix = vga16fb_fix;
1349        /* supports rectangles with widths of multiples of 8 */
1350        info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1351        info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
1352                FBINFO_HWACCEL_YPAN;
1353
1354        i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1355        ret = fb_alloc_cmap(&info->cmap, i, 0);
1356        if (ret) {
1357                printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1358                ret = -ENOMEM;
1359                goto err_alloc_cmap;
1360        }
1361
1362        if (vga16fb_check_var(&info->var, info)) {
1363                printk(KERN_ERR "vga16fb: unable to validate variable\n");
1364                ret = -EINVAL;
1365                goto err_check_var;
1366        }
1367
1368        vga16fb_update_fix(info);
1369
1370        info->apertures->ranges[0].base = VGA_FB_PHYS;
1371        info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
1372
1373        if (register_framebuffer(info) < 0) {
1374                printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1375                ret = -EINVAL;
1376                goto err_check_var;
1377        }
1378
1379        fb_info(info, "%s frame buffer device\n", info->fix.id);
1380        platform_set_drvdata(dev, info);
1381
1382        return 0;
1383
1384 err_check_var:
1385        fb_dealloc_cmap(&info->cmap);
1386 err_alloc_cmap:
1387        iounmap(info->screen_base);
1388 err_ioremap:
1389        framebuffer_release(info);
1390 err_fb_alloc:
1391        return ret;
1392}
1393
1394static int vga16fb_remove(struct platform_device *dev)
1395{
1396        struct fb_info *info = platform_get_drvdata(dev);
1397
1398        if (info)
1399                unregister_framebuffer(info);
1400
1401        return 0;
1402}
1403
1404static struct platform_driver vga16fb_driver = {
1405        .probe = vga16fb_probe,
1406        .remove = vga16fb_remove,
1407        .driver = {
1408                .name = "vga16fb",
1409        },
1410};
1411
1412static struct platform_device *vga16fb_device;
1413
1414static int __init vga16fb_init(void)
1415{
1416        int ret;
1417#ifndef MODULE
1418        char *option = NULL;
1419
1420        if (fb_get_options("vga16fb", &option))
1421                return -ENODEV;
1422
1423        vga16fb_setup(option);
1424#endif
1425        ret = platform_driver_register(&vga16fb_driver);
1426
1427        if (!ret) {
1428                vga16fb_device = platform_device_alloc("vga16fb", 0);
1429
1430                if (vga16fb_device)
1431                        ret = platform_device_add(vga16fb_device);
1432                else
1433                        ret = -ENOMEM;
1434
1435                if (ret) {
1436                        platform_device_put(vga16fb_device);
1437                        platform_driver_unregister(&vga16fb_driver);
1438                }
1439        }
1440
1441        return ret;
1442}
1443
1444static void __exit vga16fb_exit(void)
1445{
1446        platform_device_unregister(vga16fb_device);
1447        platform_driver_unregister(&vga16fb_driver);
1448}
1449
1450MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1451MODULE_LICENSE("GPL");
1452module_init(vga16fb_init);
1453module_exit(vga16fb_exit);
1454